Die Steuerung eines ChildWindow-Objektes in Silverlight wirft sehr schnell Fragen auf, wenn MVVM sauber eingesetzt werden soll. Wann ist die Eigenschaft DialogResult zu setzen und wer ist dafür verantwortlich, sind die ersten Fragen, die sich stellen.

Ansatz 1: Binding auf Eigenschaft DialogResult

Der erste Versuch liegt vermutlich darin, die Eigenschaft DialogResult des ChildWindow auf eine Eigenschaft des dahinter liegenden ViewModels zu binden. Dies wird jedoch fehl schlagen, da es sich dabei nicht um eine Dependency Property handelt. Ein Binding ist also nicht möglich. Dieser Weg scheitert hier. Eine Beschreibung dieser Eigenschaft findet sich im MSDN.

Ansatz 2: Attached Behavior

Eine funktionierende Lösung besteht darin, ein Attached Behavior zu implementieren. Dieses stellt eine Dependency Property zur Verfügung, welche auf einem ChildWindow an das dahinter liegende ViewModel gebunden werden kann. Das ViewModel selbst muss dafür eine entsprechende Eigenschaft zur Verfügung stellen.

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
#0000ff">public #0000ff">class DialogResultBehavior

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{

    #0000ff">public #0000ff">static #0000ff">readonly DependencyProperty DialogResultProperty =

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        DependencyProperty.RegisterAttached(

                "DialogResult", #0000ff">typeof(#0000ff">bool?), #0000ff">typeof(DialogResultBehavior), 

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">                #0000ff">new PropertyMetadata(DialogResultPropertyChanged)

        );

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> 

    #0000ff">private #0000ff">static #0000ff">void DialogResultPropertyChanged(

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        DependencyObject dependencyObject,

        DependencyPropertyChangedEventArgs e)

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    {

        var childWindow = dependencyObject #0000ff">as ChildWindow;

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        #0000ff">if (childWindow != #0000ff">null)

            childWindow.DialogResult = e.NewValue #0000ff">as #0000ff">bool?;

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    }

 

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    #0000ff">public #0000ff">static #0000ff">bool? GetDialogResult(ChildWindow childWindow)

    {

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        #0000ff">return childWindow.GetValue(DialogResultProperty) #0000ff">as #0000ff">bool?;

    }

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> 

    #0000ff">public #0000ff">static #0000ff">void SetDialogResult(ChildWindow childWindow, #0000ff">bool? #0000ff">value)

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    {

        childWindow.SetValue(DialogResultProperty, #0000ff">value);

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    }

}

Eingebunden wird dies im ChildWindow nun folgendermaßen:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
#0000ff"><controls:ChildWindow #ff0000">x:Class#0000ff">="DevTyr.ChildWindow.MvvmDemo.Views.DateSelectionWindow"

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">           #ff0000">xmlns#0000ff">="schemas.microsoft.com/winfx/2006/xaml/presentation" 

           #ff0000">xmlns:x#0000ff">="schemas.microsoft.com/winfx/2006/xaml" 

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">           #ff0000">xmlns:beh#0000ff">="clr-namespace:DevTyr.ChildWindow.MvvmDemo.Behaviors"

           #ff0000">beh:DialogResultBehavior.#ff0000">DialogResult#0000ff">="{Binding DialogResult}"#0000ff">>

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">           

           // Markup

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">           

#0000ff"></controls:ChildWindow#0000ff">>

In dieser Definition wird vorausgesetzt, dass das ViewModel eine Eigenschaft DialogResult bereit stellt. Diese wird durch das ViewModel mit dem korrekten Wert gesetzt. Im Normalfall geschieht dies durch an Schaltflächen gebundene Commands.

Das Ergebnis ist nun ein sauberer Weg, ein ChildWindow durch das im ViewModel implementierte Verhalten zu steuern. Wege á la Ereignishandler für das Click-Event, welche das MVVM-Pattern brechen, werden dadurch vermieden.

Über den Autor

Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler und Fotograf. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

1 Kommentar

  • Hallo Norbert,

    genau so eine Hilfestellung wie hier habe ich verzweifelt gesucht. Allerdings ist mir nicht ganz klar wie ich nun in meinem ViewModel mit dem DialogResult arbeite. Kannst du evtl. deinen Artikel noch etwas erweitern bzw. ausführen?

    LG

Cookie-Einstellungen
Auf dieser Website werden Cookie verwendet. Diese werden für den Betrieb der Website benötigt oder helfen uns dabei, die Website zu verbessern.
Alle Cookies zulassen
Auswahl speichern
Individuelle Einstellungen
Individuelle Einstellungen
Dies ist eine Übersicht aller Cookies, die auf der Website verwendet werden. Sie haben die Möglichkeit, individuelle Cookie-Einstellungen vorzunehmen. Geben Sie einzelnen Cookies oder ganzen Gruppen Ihre Einwilligung. Essentielle Cookies lassen sich nicht deaktivieren.
Speichern
Abbrechen
Essenziell (1)
Essenzielle Cookies werden für die grundlegende Funktionalität der Website benötigt.
Cookies anzeigen