2010-06-02 8 views
10

bauen I modalen Dialog einen generic/wiederverwendbarer bauen möchte, die ich in unserer WPF (MVVM) verwenden kann - WCF LOB-Anwendung.Wie ein generischen/wiederverwendbare modalen Dialog für WPF folgend MVVM

Ich habe eine Ansicht und zugehörige Viewmodel, die Ich mag würde mit Dialogen angezeigt werden soll. Bindungen zwischen Views und ViewModels erfolgen mithilfe typgezielter DataTemplates.

Hier sind einige Anforderungen, die ich erarbeiten konnte:

  • Ich ziehe diese auf einem Fenster zu beruhen statt Adorner und Kontrollen verwenden, die wie ein modaler Dialog handeln.
  • Es sollte seine Mindestgröße von den Inhalten erhalten.
  • Es sollte sich auf das Besitzerfenster zentrieren.
  • Das Fenster muss die Schaltflächen Minimieren und Maximieren nicht zeigen.
  • Es sollte seinen Titel aus dem Inhalt erhalten.

Was ist der beste Weg, dies zu tun?

Antwort

7

Ich beantworte meine eigene Frage, anderen zu helfen, alle Antworten finde ich an einem Ort zu finden, zu kämpfen. Was oben als ein geradliniges Problem erscheint, stellt tatsächlich mehrere Probleme dar, die ich im Folgenden ausreichend zu beantworten hoffe.

Hier geht.

Ihre WPF-Fenster, die als generischer Dialog dienen kann wie folgt aussehen:

<Window x:Class="Example.ModalDialogView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:ex="clr-namespace:Example" 
     Title="{Binding Path=mDialogWindowTitle}" 
     ShowInTaskbar="False" 
     WindowStartupLocation="CenterOwner" 
     WindowStyle="SingleBorderWindow" 
     SizeToContent="WidthAndHeight" 
     ex:WindowCustomizer.CanMaximize="False" 
     ex:WindowCustomizer.CanMinimize="False" 
     > 
    <DockPanel Margin="3"> 
     <StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal" FlowDirection="RightToLeft"> 
      <Button Content="Cancel" IsCancel="True" Margin="3"/> 
      <Button Content="OK" IsDefault="True" Margin="3" Click="Button_Click" /> 
     </StackPanel> 
     <ContentPresenter Name="WindowContent" Content="{Binding}"/> 
    </DockPanel> 
</Window> 

Nach MVVM, der richtige Weg, um einen Dialog zu zeigen, ist durch einen Vermittler. Um einen Mediator zu verwenden, benötigen Sie in der Regel auch einen Service Locator. Für Mediator-spezifische Details siehe here.

Die Lösung, auf die ich mich einigte, beinhaltete die Implementierung einer IDialogService-Schnittstelle, die durch einen einfachen statischen ServiceLocator aufgelöst wird. This ausgezeichnete Codeprojekt Artikel hat die Details dazu. Beachten Sie this Nachricht im Artikel Forum. Diese Lösung löst auch das Problem, das Besitzerfenster über die ViewModel-Instanz zu finden.

Mit dieser Schnittstelle können Sie IDialogService.ShowDialog (ownerViewModel, dialogViewModel) aufrufen. Fürs Erste rufe ich dies vom Eigentümer ViewModel, was bedeutet, dass ich harte Referenzen zwischen meinen ViewModels habe.Wenn Sie aggregierte Ereignisse verwenden, werden Sie diese wahrscheinlich von einem Leiter anrufen.

Durch Festlegen der Mindestgröße für die Ansicht, die schließlich im Dialogfeld angezeigt wird, wird die Mindestgröße des Dialogfelds nicht automatisch festgelegt. Da die logische Struktur im Dialogfeld das ViewModel enthält, können Sie nicht nur an die Eigenschaften des WindowContent-Elements binden. This Frage hat eine Antwort mit meiner Lösung.

Die Antwort, die ich oben erwähne, enthält auch Code, der das Fenster auf den Besitzer zentriert.

Abschließend ist das Deaktivieren der Schaltflächen zum Minimieren und Maximieren etwas, das WPF nicht nativ ausführen kann. Die eleganteste Lösung, die IMHO verwendet, ist this.

11

ich in der Regel damit umgehen, indem Sie diese Schnittstelle in das entsprechende Viewmodel Injektion:

public interface IWindow 
{ 
    void Close(); 

    IWindow CreateChild(object viewModel); 

    void Show(); 

    bool? ShowDialog(); 
} 

Dies ermöglicht es das Viewmodel Kind Fenster SPAW und sie modal auf modales zeigen.

Eine wiederverwendbare Implementierung von IWindow ist dies:

public class WindowAdapter : IWindow 
{ 
    private readonly Window wpfWindow; 

    public WindowAdapter(Window wpfWindow) 
    { 
     if (wpfWindow == null) 
     { 
      throw new ArgumentNullException("window"); 
     } 

     this.wpfWindow = wpfWindow; 
    } 

    #region IWindow Members 

    public virtual void Close() 
    { 
     this.wpfWindow.Close(); 
    } 

    public virtual IWindow CreateChild(object viewModel) 
    { 
     var cw = new ContentWindow(); 
     cw.Owner = this.wpfWindow; 
     cw.DataContext = viewModel; 
     WindowAdapter.ConfigureBehavior(cw); 

     return new WindowAdapter(cw); 
    } 

    public virtual void Show() 
    { 
     this.wpfWindow.Show(); 
    } 

    public virtual bool? ShowDialog() 
    { 
     return this.wpfWindow.ShowDialog(); 
    } 

    #endregion 

    protected Window WpfWindow 
    { 
     get { return this.wpfWindow; } 
    } 

    private static void ConfigureBehavior(ContentWindow cw) 
    { 
     cw.WindowStartupLocation = WindowStartupLocation.CenterOwner; 
     cw.CommandBindings.Add(new CommandBinding(PresentationCommands.Accept, (sender, e) => cw.DialogResult = true)); 
    } 
} 

Sie dieses Fenster als wiederverwendbare Host-Fenster verwenden können. Es gibt keinen Code-Behind:

<Window x:Class="Ploeh.Samples.ProductManagement.WpfClient.ContentWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:self="clr-namespace:Ploeh.Samples.ProductManagement.WpfClient" 
     xmlns:pm="clr-namespace:Ploeh.Samples.ProductManagement.PresentationLogic.Wpf;assembly=Ploeh.Samples.ProductManagement.PresentationLogic.Wpf" 
     Title="{Binding Path=Title}" 
     Height="300" 
     Width="300" 
     MinHeight="300" 
     MinWidth="300" > 
    <Window.Resources> 
     <DataTemplate DataType="{x:Type pm:ProductEditorViewModel}"> 
      <self:ProductEditorControl /> 
     </DataTemplate> 
    </Window.Resources> 
    <ContentControl Content="{Binding}" /> 
</Window> 

Sie können mehr über diese Zeilen lesen (sowie die vollständige Codebeispiel herunterladen) in my book.

+0

Vielen Dank für Ihre Herangehensweise! –

+0

Warum der anonyme Downvote? –