Cómo: Desechar una Vista (SmartPart) en CAB y SCSF (Dispose a View)
En el foro de Smart Client en Codeplex, varios han preguntado cómo desechar una vista. Además, varias soluciones fueron propuestas.
La solución más rápida era extender el método CloseView() en el Presenter (de la Vista que queríamos desechar) de la siguiente manera:
public void OnCloseView()
{
base.CloseView();
WorkItem.SmartParts.Remove(View); //Removes the view from the SmartPart collection.
if (View is IDisposable) ((IDisposable)View).Dispose(); //Disposes the view.
}
Sin embargo, quizás querramos desechar cualquier vista cada vez que la cerremos, por lo que la mejor forma de lograr ésto es mandando este código a la clase base Presenter localizada en el proyecto Infrastructure.Interface. JochenZ me mostró una forma ampliada de hacerlo (en el tópico SmartParts do not get disposed on WorkItem.Terminate(), en Codeplex). En su código, JochenZ consideró la posibilidad de que algún subscriptor al evento SmartPartClosing quizás haya establecido la propiedad Cancel en True, evitando que la Vista se cerrara. Es un código bien hecho, así que lo citaré:
protected virtual void CloseView()
{
Services.IWorkspaceLocatorService locator = WorkItem.Services.Get<Services.IWorkspaceLocatorService>();
IWorkspace wks = locator.FindContainingWorkspace(WorkItem, View);
if (wks != null) wks.Close(View);
// check whether the view was actually closed (a subscriber to the IWorkspace.SmartPartClosing event might have cancelled it)
wks = locator.FindContainingWorkspace(WorkItem, View);
// if the view was removed from the workspace, remove it from the smartparts collection and dispose it if possible
if (wks == null) {
WorkItem.SmartParts.Remove(View);
IDisposable viewAsDisposable = View as IDisposable;
if (viewAsDisposable != null) viewAsDisposable.Dispose();
}
}
Debo admitir que encuentro bastante interesante el código citado arriba, pero también debo decir que las soluciones propuestas hasta aquí presentan una falla. Como podemos ver, el método CloseView() llama al método IWorkspace.Close(smartPart) para cerrar la vista (obviamente
). Pero, ¿qué pasaría si un botón, por ejemplo, en otro lugar (por así decirlo, en el Shell o en otra vista) llamara directamente al método IWorkspace.Close(smartPart)? ¡No habría llamada al método CloseView() por lo que la vista no se desecharía! Por lo tanto, necesitamos encontrar un nuevo hogar para el procedimiento de disposing.
Un nuevo hogar podría ser una clase que proveyera un método estático para hacer el disposing, la cuál podríamos ubicar en el proyecto Infrastructure.Interface (por razones de uso
). El código resultante debería verse así:
public class ViewDisposer
{
///
/// Disposes the closing view.
///
/// Closing SmartPart.
/// Container WorkItem.
public static void DiposeView(object smartPart, WorkItem workItem)
{
IDisposable viewAsDisposable = smartPart as IDisposable;
if (viewAsDisposable != null) viewAsDisposable.Dispose();
workItem.SmartParts.Remove(smartPart);
}
}
Una vez que tenemos ésto, podemos utilizarlo así (por ejemplo):
WorkItem.Workspaces[WorkspaceNames.RightWorkspace].SmartPartClosing += new EventHandler<WorkspaceCancelEventArgs>(
delegate(object workspace, WorkspaceCancelEventArgs e)
{
ViewDisposer.DisposeView(e.SmartPart, WorkItem);
});
Por favor, recuerden que deben considerar cuándo y dónde hacer el disposing (si no quieren hacerlo todo el tiempo). Además, si se posiciona este handler en la primera posición (en cuanto a orden de handlers), no se podrá cancelar el diposing, por lo que recomiendo usar ésto cuidadosamente y, por supuesto, a conciencia!
- Salu2, Nacho
See this topic in English.