简体   繁体   中英

Which is the best way for creating new windows using the MVVM design pattern

I want to ask which is the best way to show child windows using the MVVM pattern and the MVVMLight framework. I have read a couple of threads here in this site but I don't seem to comprehence what exactly the code written is doing, so please provide a detailed explanation with your ideas.

i use a service to show new windows or new dialogs.

you can check my first version for dialogs here

i added some more overloads to my interface the last days

public interface IUIDialogWindowService
{
    ///<summary>
    /// Zeigt ein Dialog an.
    ///</summary>
    ///<param name="titel">Titel für den Dialog</param>
    ///<param name="datacontext">DataContext für den Dialog</param>
    ///<returns>true wenn DialogResult=true, ansonsten false</returns>
    bool? ShowDialog(string titel, object datacontext);

    ///<summary>
    /// Zeigt ein Dialog an.
    ///</summary>
    ///<param name="titel">Titel für den Dialog</param>
    ///<param name="datacontext">DataContext für den Dialog</param>
    ///<param name="minHeigth">Minimum Height</param>
    ///<param name="minWidth">Minimum Width</param>
    ///<param name="maxHeigth">Maximum Height</param>
    ///<param name="maxWidth">Maximum Width</param>
    ///<returns>true wenn DialogResult=true, ansonsten false</returns>
    bool? ShowDialog(string titel, object datacontext, double minHeigth = 0, double minWidth=0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity);


    /// <summary>
    /// Zeigt ein Dialog an
    /// </summary>
    /// <param name="titel">Titel für den Dialog<</param>
    /// <param name="datacontext">DataContext für den Dialog</param>
    /// <param name="settings">ApplicationsSetting für Height and Width</param>
    /// <param name="pathHeigthSetting">Name für Height Setting</param>
    /// <param name="pathWidthSetting">Name für Width Setting</param>
    /// <param name="minHeigth">Minimum Height</param>
    /// <param name="minWidth">Minimum Width</param>
    /// <param name="maxHeigth">Maximum Height</param>
    /// <param name="maxWidth">Maximum Width</param>
    /// <returns>true wenn DialogResult=true, ansonsten false</returns>
    bool? ShowDialog(string titel, object datacontext, ApplicationSettingsBase settings, string pathHeigthSetting, string pathWidthSetting, double minHeigth = 0, double minWidth = 0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity);
}


///<summary>
/// Implementierung von <see cref="IUIDialogWindowService"/>
///</summary>
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(IUIDialogWindowService))]
public class WpfUIDialogWindowService : IUIDialogWindowService
{
    #region Implementation of IUIDialogWindowService

    ///<summary>
    /// Zeigt ein Dialog an.
    ///</summary>
    ///<param name="titel">Titel für den Dialog</param>
    ///<param name="datacontext">DataContext für den Dialog</param>
    ///<returns>true wenn DialogResult=true, ansonsten false</returns>
    public bool? ShowDialog(string titel, object datacontext)
    {
        var win = new DialogWindow {Title = titel, DataContext = datacontext};

        return win.ShowDialog();
    }

    ///<summary>
    /// Zeigt ein Dialog an.
    ///</summary>
    ///<param name="titel">Titel für den Dialog</param>
    ///<param name="datacontext">DataContext für den Dialog</param>
    ///<param name="minHeigth">Minimum Height</param>
    ///<param name="minWidth">Minimum Width</param>
    ///<param name="maxHeigth">Maximum Height</param>
    ///<param name="maxWidth">Maximum Width</param>
    ///<returns>true wenn DialogResult=true, ansonsten false</returns>
    public bool? ShowDialog(string titel, object datacontext, double minHeigth = 0, double minWidth = 0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity)
    {
        var win = new DialogWindow { Title = titel, DataContext = datacontext };

        win.MinHeight = minHeigth;
        win.MinWidth = minWidth;
        win.MaxHeight = maxHeigth;
        win.MaxWidth = maxWidth;

        return win.ShowDialog();
    }

    /// <summary>
    /// Zeigt ein Dialog an
    /// </summary>
    /// <param name="titel">Titel für den Dialog<</param>
    /// <param name="datacontext">DataContext für den Dialog</param>
    /// <param name="settings">ApplicationsSetting für Height and Width</param>
    /// <param name="pathHeigthSetting">Name für Height Setting</param>
    /// <param name="pathWidthSetting">Name für Width Setting</param>
    /// <param name="minHeigth">Minimum Height</param>
    /// <param name="minWidth">Minimum Width</param>
    /// <param name="maxHeigth">Maximum Height</param>
    /// <param name="maxWidth">Maximum Width</param>
    /// <returns>true wenn DialogResult=true, ansonsten false</returns>
    public bool? ShowDialog(string titel, object datacontext, ApplicationSettingsBase settings, string pathHeigthSetting, string pathWidthSetting, double minHeigth = 0, double minWidth = 0, double maxHeigth = double.PositiveInfinity, double maxWidth = double.PositiveInfinity)
    {
        var win = new DialogWindow { Title = titel, DataContext = datacontext };

        win.MinHeight = minHeigth;
        win.MinWidth = minWidth;
        win.MaxHeight = maxHeigth;
        win.MaxWidth = maxWidth;

        try
        {
            if(settings != null)
            {
                win.SizeToContent = SizeToContent.Manual;

                var height = settings[pathHeigthSetting];
                var width = settings[pathWidthSetting];

                BindingOperations.SetBinding(win, FrameworkElement.HeightProperty, new Binding(pathHeigthSetting) { Source = settings, Mode = BindingMode.TwoWay });
                BindingOperations.SetBinding(win, FrameworkElement.WidthProperty, new Binding(pathWidthSetting) { Source = settings, Mode = BindingMode.TwoWay });

                win.Height = (double)height;
                win.Width = (double)width;
            }
        }
        catch
        {
            win.SizeToContent = SizeToContent.WidthAndHeight;
        }

        return win.ShowDialog();
    }





    #endregion
}

For the sake of completeness:

<Window x:Class="DialogWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
    WindowStyle="SingleBorderWindow" 
    WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight"
    Style="{DynamicResource {x:Type Window}}">
<ContentPresenter x:Name="DialogPresenter" Content="{Binding .}">

</ContentPresenter>
</Window>

public partial class DialogWindow : Window
{
    public DialogWindow()
    {
        InitializeComponent();
        this.DialogPresenter.DataContextChanged += DialogPresenterDataContextChanged;
    }



    private void DialogPresenterDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var d = e.NewValue as IDialogResultVMHelper;

        if (d == null)
            return;

        d.RequestCloseDialog += new EventHandler<RequestCloseDialogEventArgs>(DialogResultTrueEvent).MakeWeak(eh => d.RequestCloseDialog -= eh);
    }

    private void DialogResultTrueEvent(object sender, RequestCloseDialogEventArgs eventargs)
    {
        this.DialogResult = eventargs.DialogResult;
    }
}

public class RequestCloseDialogEventArgs : EventArgs
{
    public RequestCloseDialogEventArgs(bool dialogresult)
    {
        this.DialogResult = dialogresult;
    }

    public bool DialogResult
    {
        get; set;
    }
}

public interface IDialogResultVMHelper
{
    event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}

First a question, and a counter-intuitive one. What does the opening a new window action have to do with MVVM?

I personally don't think there is any connection at all. In fact like several other UI constructs, it's something that happens totally in the View layer. There are several other concepts like this,

  • A navigation based interface (using NavigationWindow) where data is filled into a form and Next is pressed in order to change to the next page
  • A context menu that opens with a variable set of operations
  • A tabbed control that dynamically loads the active page

All of these things are different ways of displaying new views to the user. All of them exist in the View tier only by presenting new UI elements that are bound to ViewModels.

However... there are lots of patterns that have evolved around MVVM to support this. Commonly this is the use of a service or a controller to handle the view operations, check to see if the MVVM library of your choice supports means of showing a new view.

Finally one thing that caught me out for a while, is what happens when you need to both perform an operation and change the view. Normally you would bind the UI object (eg a button) to a ViewModel level command to perform the action, and rely on binding to update the UI controls showing the new values. Since the ViewModel shouldn't know about the View then any operations that change the UI have to occur solely in the View. This means that you can't bind to a ViewModel command. Fortunately you can create a command at the view level that delegates to the view model level operation and changes the UI.

(Hmm... Reading back, not sure this answers the question, but it might help clarify your thinking)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM