2009-02-17 10 views
5

Ein-Zeilen-Zusammenfassung: Was ist die beste Vorgehensweise zum Abhängen von Ereignishandlern, die im Konstruktor eines Benutzersteuerelements in Silverlight2 erstellt wurden?Wann sollten Ereignisse in Silverlight ausgehängt werden?

Hintergrund: Ich bin gerade dabei, eine Line-of-Business-Anwendung in Silverlight2 zu erstellen. Da Silverlight ein Browser-Plugin ist, gibt es kein Konzept für ein Fenster - alles wird in UserControls gemacht. Die Art, wie ich verschiedene "Formulare" in der Anwendung handhabe, ist eine Benutzersteuerung auf oberster Ebene, die eine Viewbox enthält. Um verschiedene Formulare anzuzeigen, setze ich die Child-Eigenschaft der Viewbox auf verschiedene UserControls. Meine App verfügt über eine Singleton PageManager-Klasse, die zum Öffnen und Schließen von Formularen aufgerufen wird. Die Formulare (UserControls) sind in einem Stapel gespeichert. Wenn Sie ein Formular öffnen, wird es oben auf den Stapel gelegt. Wenn Sie es schließen, wird es vom Stapel entfernt und der darunter liegende angezeigt.

Ich versuche, das Model-View-ViewModel-Muster zu folgen. In jedem Formular (abgeleitet von UserControl) habe ich ein ViewModel, das alle Daten für die Ansicht verwaltet. Das ViewModel macht Ereignisse verfügbar, sodass die Benutzeroberfläche benachrichtigt werden kann, wenn Vorgänge wie Laden und Speichern abgeschlossen sind.

In meiner Form, ich subscribe im Konstruktor auf das Ereignis, nachdem ich das Ansichtsmodell

public partial class MyPage : UserControl 
{ 

    public MyViewModel ViewModel{get; set;} 

    // other constructors, which create the viewmodel and call the constructor below. 

    public MyPage(MyViewModel viewModel) 
    { 
     InitializeComponent(); 
     ViewModel = viewModel; 
     this.LayoutRoot.DataContext = this.ViewModel; 

     // subscribe to event so we can do stuff 
     this.ViewModel.LoadCompleted += new MyViewModel.LoadCompletedEventHandler(ViewModel_LoadCompleted); 
    } 

Meine Frage ist haben: Nun, da ich auf dieses Ereignis abonniert haben, wenn entferne ich die Handler? Erstelle ich einen Destruktor und tue es dort, oder erzeugt das eine Hühner-und-Ei-Situation, in der der Müllsammler das Objekt nicht zerstören wird, bis alle Referenzen (dh die Event-Handler) verschwunden sind? Erstelle ich eine Schnittstelle, die die Formulare implementieren müssen, die eine UnhookEvents-Funktion angibt, die aufgerufen wird, wenn das Formular vom PageManager geschlossen wird?

Bearbeiten: Vielen Dank für die Antworten. Was ist mit der Situation, in der das ViewModel länger als das Formular (UserControl) dauert? Ein Teil meiner App erlaubt es Benutzern, eine ziemlich komplexe Struktur zu erstellen, aber in 95% der Fälle ist es viel einfacher. Ich habe zwei Formulare erstellt, die dasselbe ViewModel verwenden. Benutzer können damit beginnen, das einfache Formular auszufüllen und dann in den erweiterten Modus zu wechseln, der ein neues Formular erstellt und das ViewModel an dieses Formular weitergibt.

In dem einfachen Setup-Form:

private void AdvancedSessionSetupButton_Click(object sender, RoutedEventArgs e) 
    { 
     PageManager.GetPageManager().Close(this); 
     PageManager.GetPageManager().Open(new CreateSessionPage(this.ViewModel), "Create Session"); 
    } 

im erweiterten Setup-Form:

private void BasicSessionSetupButton_Click(object sender, RoutedEventArgs e) 
    { 
     PageManager.GetPageManager().Close(this); 
     PageManager.GetPageManager().Open(new CreateBasicSessionPage(this.ViewModel), "Create Session"); 
    } 

Nach PageManager.Close, die einzigen Dinge, Referenzierung der Form sind die Ereignisse innerhalb des Ansichtsmodell. Ich nehme an, dort sollte ich sie aushaken.

Antwort

2

A destructor, besser bekannt zu C# Programmierer als:

this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted; 

Sie eine destructor implementieren Finalizer, ist in diesem Fall nicht notwendig. Unter der Annahme, dass ViewModel_LoadCompleted eine Memberfunktion ist, enthält es einen Zeiger auf "this", den Sie dem ViewModel-Objekt geben, das vollständig von "this" enthalten ist. Der Garbage Collector sollte dies intelligent ignorieren.

In diesem Fall ist es die richtige Sache, keine Zeit damit zu verschwenden, sie zu lösen.

Im Allgemeinen müssen Sie eine Ereignisbehandlungsroutine lösen, wenn Sie "this" (explizit oder implizit) an ein Objekt übergeben, das diese Referenz länger als die beabsichtigte Lebensdauer von "this" enthält. Wenn Sie beispielsweise einen Handler für das Ereignis eines übergeordneten Steuerelements festlegen. Jetzt hat der Elternteil einen Verweis auf Sie über den Handler sowie in seiner Children-Steuerelementsammlung. In diesem Fall sollten Sie die Bindung trennen, wenn Sie vom übergeordneten Objekt entfernt werden.

Im Zweifelsfall IDisposable und unbind im Aufruf von Dispose() implementieren.

+0

Typo, "descructor" –

+0

Was passiert, wenn mein ViewModel länger als das UserControl dauert? (Ich werde die Frage bearbeiten, um zu zeigen, wie) – geofftnz

+0

Wenn Ihr Modell länger als die Benutzersteuerung dauert, müssen Sie sich dann auch keine Gedanken über die Aufhebung machen. Das Modell sollte keinen Bezug zum Steuerelement haben. Wenn das Steuerelement den Gültigkeitsbereich verlässt, wird es Müll gesammelt und zeigt nicht mehr auf das Modell. –

1

Ereignisse werden automatisch aufgehoben, wenn der Garbage Collector Ihr Objekt durchläuft.

Aber man kann sie explizit mit dem unbind - jederzeit Syntax "=":

~MyPage 
{ 
    this.ViewModel.LoadCompleted -= ViewMode_LoadCompleted; 
}