【问题标题】:Which is the best way for creating new windows using the MVVM design pattern哪个是使用 MVVM 设计模式创建新窗口的最佳方式
【发布时间】:2013-11-27 07:53:17
【问题描述】:

我想问一下使用 MVVM 模式和 MVVMLight 框架显示子窗口的最佳方式是什么。我在这个网站上阅读了几个主题,但我似乎不理解所编写的代码到底在做什么,所以请提供你的想法的详细解释。

【问题讨论】:

  • 到目前为止你有什么要展示的吗?有一些很好的例子:Link 1 | Link 2

标签: c# wpf windows mvvm


【解决方案1】:

我使用服务来显示新窗口或新对话框。

你可以查看我的第一个版本的对话框here

最近几天我在界面中添加了更多重载

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
}

为了完整起见:

<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;
}

【讨论】:

  • 能否提供cmets的英文翻译
  • 你不明白哪些cmets?
  • 好吧,我确实说过我是新手,所以大部分内容我都无法理解
【解决方案2】:

首先是一个问题,一个反直觉的问题。打开一个新窗口的动作和MVVM有什么关系?

我个人认为根本没有任何联系。事实上,就像其他几个 UI 结构一样,它完全发生在 View 层中。还有其他几个类似的概念,

  • 基于导航的界面(使用 NavigationWindow)将数据填充到表单中并按下 Next 以切换到下一页
  • 打开的上下文菜单包含一组可变的操作
  • 动态加载活动页面的选项卡式控件

所有这些都是向用户显示新视图的不同方式。它们都存在于 View 层中,仅通过呈现绑定到 ViewModel 的新 UI 元素。

但是...围绕 MVVM 发展了许多模式来支持这一点。通常这是使用服务或控制器来处理视图操作,检查您选择的 MVVM 库是否支持显示新视图的方式。

最后一件事让我很困惑,当您需要执行操作和更改视图时会发生什么。通常,您会将 UI 对象(例如按钮)绑定到 ViewModel 级别的命令以执行操作,并依靠绑定来更新显示新值的 UI 控件。由于 ViewModel 不应该知道 View,因此任何更改 UI 的操作都必须单独发生在 View 中。这意味着您不能绑定到 ViewModel 命令。幸运的是,您可以在视图级别创建一个命令,委托给视图模型级别的操作并更改 UI。

(嗯...回读,不确定这是否能回答问题,但它可能有助于澄清您的想法)

【讨论】:

  • 据我所知,有些东西可以写在代码隐藏中,就像打开和关闭另一个视图一样,因为在这种情况下与任何视图模型都没有连接,对吗
  • 是的,虽然我并不是说代码隐藏是编写 UI 的正确方法,但这确实有效。如果您决定采用您的应用程序并用不同的视图替换整个视图,请考虑它应该意味着什么(对您的 VM 和 M)。例如您希望向导引导新用户完成这些步骤,但需要一个高级用户对话框。它们应该做同样的事情并绑定到相同的 ViewModel 数据,但只是看起来不同。
猜你喜欢
  • 2011-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多