Das gezeigte Beispiel basiert auf das in diesem Artikel (und den verlinkten) gezeigte Mini-MVVM-Framework. Die entsprechende Abhängigkeit ist in dem hier angefügten Projekt vorhanden. Wer sich den Source bzw. die Funktionalität genauer ansehen möchte, sei auf den Artikel verwiesen.
Eine in der MVVM-Welt häufig gestellte Frage ist, wie Popups geöffnet werden können, ohne das Pattern selbst zu verletzen. Dieser Artikel möchte auf diese Frage eingehen und eine Lösung dafür vorschlagen.
Hinweis: Ich selbst bin in der Regel dazu übergegangen Popups anzuzeigen und keine eigenständigen Fenster. Dies ist zwar oftmals abhängig von den Anforderungen, aber sehr oft ein guter Weg, damit der Kontext (auch für den Benutzer) zu erhalten.
Im angehängten Beispiel gibt es ein Hauptfenster, an welches ein ViewModel gebunden wird. Dieses ViewModel soll die Steuerung für das Popup übernehmen. Dafür werden zwei Commands angeboten:
- OpenHelpCommand
- CloseHelpCommand
Beide setzen eine Eigenschaft IsHelpVisible
, die öffentlich verfügbar ist und in weiterer Folge von der View verwendet wird, um das dort vorhandene Popup sichtbar zu stellen oder wieder zu verstecken.
[LocatorAttribute("MainViewModel")]
public class MainViewModel : ViewModelBase
{
private ICommand openHelpCommand;
private ICommand closeHelpCommand;
private bool isHelpVisible;
public ICommand OpenHelpCommand
{
get
{
if (openHelpCommand == null)
openHelpCommand = new RelayCommand(OpenHelp);
return openHelpCommand;
}
}
private void OpenHelp(object param)
{
IsHelpVisible = true;
}
public ICommand CloseHelpCommand
{
get
{
if (closeHelpCommand == null)
closeHelpCommand = new RelayCommand(CloseHelp);
return closeHelpCommand;
}
}
private void CloseHelp(object param)
{
IsHelpVisible = false;
}
public bool IsHelpVisible
{
get { return isHelpVisible; }
set
{
if (isHelpVisible == value)
return;
isHelpVisible = value;
RaisePropertyChanged("IsHelpVisible");
}
}
}
Nachfolgend ist eine Abbildung des Fensters zu sehen, welche den Aufbau beschreibt:
Dabei wird ein Grid
-Element verwendet, um die einzelnen Elemente der View anzuordnen. Die Schaltfläche am unteren Rand des Fensters ist an den Command OpenHelpCommand
gebunden und löst bei Betätigung die dortige Execute
-Aktion aus. Innerhalb des Grids befindet sich zusätzlich die Definition des Popups. Dazu wird das Popup
-Element verwendet.
<Popup Placement="Center" IsOpen="{Binding IsHelpVisible}">
<Border Style="{StaticResource PopupBorder}">
<StackPanel>
<TextBlock Text="Help" FontSize="28" FontWeight="ExtraBold" HorizontalAlignment="Center"/>
<TextBlock Text="Use the button below to close this window." Margin="5 30 5 5"/>
<Button Content="Close Popup" Command="{Binding CloseHelpCommand}"/>
</StackPanel>
</Border>
</Popup>
Die Eigenschaft IsOpen
des Popups ist an die Eigenschaft IsHelpVisible
des ViewModels gebunden, welche durch die beiden erwähnten Commands entsprechend gesetzt wird. Der initiale Wert ist false
. Somit wird das Popup nicht angezeigt. Wird nun die Schaltfläche betätigt, werden beide Eigenschaften auf true
gestellt und somit das Popup angezeigt.
Das Popup selbst enthält nun ebenfalls eine Schaltfläche. Diese ist an den Command CloseHelpCommand
gebunden. Wird diese betätigt, werden die Eigenschaften für die Steuerung des Popups auf false
gesetzt und das Popup verschwindet wieder.
Fazit
Durch diese Lösung wird das Popup in der View definiert, die Steuerung erfolgt jedoch komplett über das ViewModel. Referenzen auf Elemente der View sind für das ViewModel nicht notwendig, wodurch das MVVM-Pattern nicht verletzt wird. Zusätzlich ist dadurch eine einfache Möglichkeit gegeben, mit dem Benutzer zu interagieren oder Daten bearbeiten zu lassen.
Wie gewohnt ist im Anhang wieder das gesamte Beispiel als Download verfügbar. Über Anregungen, Ideen und Kritik würde ich mich natürlich sehr freuen.