C# 使用MVVM在wpf中进行对话的好做法还是坏做法?

C# 使用MVVM在wpf中进行对话的好做法还是坏做法?,c#,.net,wpf,mvvm,modal-dialog,C#,.net,Wpf,Mvvm,Modal Dialog,我最近遇到了为我的wpf应用程序创建添加和编辑对话框的问题 我想在代码中做的就是这样的事情。(我主要在mvvm中使用viewmodel-first方法) 调用对话框窗口的ViewModel: var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM); // Do anything with the dialog result 它是如何工作的 首先,我创建了一个对话服务: public i

我最近遇到了为我的wpf应用程序创建添加和编辑对话框的问题

我想在代码中做的就是这样的事情。(我主要在mvvm中使用viewmodel-first方法)

调用对话框窗口的ViewModel:

var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
// Do anything with the dialog result
它是如何工作的

首先,我创建了一个对话服务:

public interface IUIWindowDialogService
{
    bool? ShowDialog(string title, object datacontext);
}

public class WpfUIWindowDialogService : IUIWindowDialogService
{
    public bool? ShowDialog(string title, object datacontext)
    {
        var win = new WindowDialog();
        win.Title = title;
        win.DataContext = datacontext;

        return win.ShowDialog();
    }
}
WindowDialog
是一个特殊但简单的窗口。我需要它来保存我的内容:

<Window x:Class="WindowDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    Title="WindowDialog" 
    WindowStyle="SingleBorderWindow" 
    WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight">
    <ContentPresenter x:Name="DialogPresenter" Content="{Binding .}">

    </ContentPresenter>
</Window>
每当我的ViewModel认为是时候执行
dialogresult=true
,然后引发此事件

public partial class DialogWindow : Window
{
    // Note: If the window is closed, it has no DialogResult
    private bool _isClosed = false;

    public DialogWindow()
    {
        InitializeComponent();
        this.DialogPresenter.DataContextChanged += DialogPresenterDataContextChanged;
        this.Closed += DialogWindowClosed;
    }

    void DialogWindowClosed(object sender, EventArgs e)
    {
        this._isClosed = true;
    }

    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)
    {
        // Important: Do not set DialogResult for a closed window
        // GC clears windows anyways and with MakeWeak it
        // closes out with IDialogResultVMHelper
        if(_isClosed) return;

        this.DialogResult = eventargs.DialogResult;
    }
 }
好了,就这些,我现在可以从我的viewmodels调用对话框:

 var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
现在我的问题是,你认为这个解决方案有什么问题吗

编辑:为了完整性。ViewModel应该实现
IDialogResultVMHelper
,然后它可以在
OkCommand
或类似的命令中提升它:

public class MyViewmodel : IDialogResultVMHelper
{
    private readonly Lazy<DelegateCommand> _okCommand;

    public MyViewmodel()
    {
         this._okCommand = new Lazy<DelegateCommand>(() => 
             new DelegateCommand(() => 
                 InvokeRequestCloseDialog(
                     new RequestCloseDialogEventArgs(true)), () => 
                         YourConditionsGoesHere = true));
    }

    public ICommand OkCommand
    { 
        get { return this._okCommand.Value; } 
    }

    public event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
    private void InvokeRequestCloseDialog(RequestCloseDialogEventArgs e)
    {
        var handler = RequestCloseDialog;
        if (handler != null) 
            handler(this, e);
    }
 }
公共类MyViewmodel:IDialogResultVMHelper
{
private readonly Lazy\u命令;
公共MyViewmodel()
{
这个._okCommand=newlazy(()=>
新的DelegateCommand(()=>
InvokeRequestCloseDialog(
新建RequestCloseDialogEventArgs(true)),()=>
您的条件goesher=true);
}
公共ICommand命令
{ 
获取{返回此。\u okCommand.Value;}
}
公共事件事件处理程序RequestCloseDialog;
私有void InvokeRequestCloseDialog(RequestCloseDialogEventArgs e)
{
var handler=RequestCloseDialog;
if(处理程序!=null)
处理者(本,e);
}
}
编辑2:我使用这里的代码使我的EventHandler注册弱:

(网站已不存在,)

public委托void UnregisterCallback(EventHandler EventHandler)
其中TE:EventArgs;
公共接口IWeakEventHandler
其中TE:EventArgs
{
EventHandler处理程序{get;}
}
公共类WeakEventHandler:IWeakEventHandler
T:在哪里上课
其中TE:EventArgs
{
私有委托void OpenEventHandler(T@this,对象发送者,TE e);
私有只读WeakReference mTargetRef;
私有只读OpenEventHandler-mOpenHandler;
私有只读事件处理程序mHandler;
私有未注册寄存器;
公共事件处理程序(EventHandler,
取消注册回调(取消注册)
{
mTargetRef=新的WeakReference(eventHandler.Target);
mOpenHandler=(OpenEventHandler)Delegate.CreateDelegate(
typeof(OpenEventHandler),null,eventHandler.Method);
mHandler=调用;
mUnregister=取消注册;
}
公共void调用(对象发送方,TE e)
{
T target=(T)mTargetRef.target;
如果(目标!=null)
调用(目标、发送方、e);
else if(mUnregister!=null)
{
蒙利斯特(mHandler);
munlister=null;
}
}
公共事件处理程序
{
获取{return mHandler;}
}
公共静态隐式运算符EventHandler(WeakEventHandler-weh)
{
返回weh.mHandler;
}
}
公共静态类EventHandlerUtils
{
public static EventHandler MakeWeak(此EventHandler EventHandler,
取消注册回调(取消注册)
其中TE:EventArgs
{
if(eventHandler==null)
抛出新ArgumentNullException(“eventHandler”);
if(eventHandler.Method.IsStatic | | eventHandler.Target==null)
抛出新ArgumentException(“仅支持实例方法”,
“事件处理人”);
var wehType=typeof(WeakEventHandler)。MakeGenericType(
eventHandler.Method.DeclaringType,typeof(TE));
var wehConstructor=wehType.GetConstructor(新类型[])
{ 
typeof(EventHandler),typeof(UnregisterCallback)
});
IWeakEventHandler weh=(IWeakEventHandler)wehConstructor.Invoke(
新对象[]{eventHandler,unregister});
返回weh.Handler;
}
}

这是一个很好的方法,我过去也使用过类似的方法。加油

我肯定要做的一件小事是,当您需要在DialogResult中设置“false”时,让事件接收一个布尔值

event EventHandler<RequestCloseEventArgs> RequestCloseDialog;

几个月来,我一直在使用几乎相同的方法,对此我非常满意(即,我还没有感觉到完全重写它的冲动…)


在我的实现中,我使用了一个
IDialogViewModel
,它公开了诸如标题、要显示的standad按钮(以便在所有对话框中具有一致的外观)、一个
RequestClose
事件,还有一些其他的东西可以控制窗口的大小和行为

如果你在谈论对话窗口而不仅仅是弹出消息框,请考虑下面的方法。重点是:

  • 我将对
    模块控制器的引用
    传递到每个
    视图模型的构造函数中(您可以使用注入)
  • 模块控制器具有创建对话窗口的公共/内部方法(仅创建,不返回结果)。因此,要在
    ViewModel
    中打开一个对话窗口,我写:
    controller.OpenDialogEntity(bla,bla…)
  • 每个对话窗口都会通过以下方式通知其结果(如确定、保存、取消等)。如果您使用PRISM,那么使用它发布通知会更容易
  • 为了处理对话结果,我使用了通知订阅(同样是PRISM)。要减少对此类通知的依赖,请使用带有标准通知的独立类
  • 优点:

    • 更少的代码。我不介意使用接口,但我见过太多项目过度使用inte
      public class MyViewmodel : IDialogResultVMHelper
      {
          private readonly Lazy<DelegateCommand> _okCommand;
      
          public MyViewmodel()
          {
               this._okCommand = new Lazy<DelegateCommand>(() => 
                   new DelegateCommand(() => 
                       InvokeRequestCloseDialog(
                           new RequestCloseDialogEventArgs(true)), () => 
                               YourConditionsGoesHere = true));
          }
      
          public ICommand OkCommand
          { 
              get { return this._okCommand.Value; } 
          }
      
          public event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
          private void InvokeRequestCloseDialog(RequestCloseDialogEventArgs e)
          {
              var handler = RequestCloseDialog;
              if (handler != null) 
                  handler(this, e);
          }
       }
      
      public delegate void UnregisterCallback<TE>(EventHandler<TE> eventHandler) 
          where TE : EventArgs;
      
      public interface IWeakEventHandler<TE> 
          where TE : EventArgs
      {
          EventHandler<TE> Handler { get; }
      }
      
      public class WeakEventHandler<T, TE> : IWeakEventHandler<TE> 
          where T : class 
          where TE : EventArgs
      {
          private delegate void OpenEventHandler(T @this, object sender, TE e);
      
          private readonly WeakReference mTargetRef;
          private readonly OpenEventHandler mOpenHandler;
          private readonly EventHandler<TE> mHandler;
          private UnregisterCallback<TE> mUnregister;
      
          public WeakEventHandler(EventHandler<TE> eventHandler,
                                      UnregisterCallback<TE> unregister)
          {
              mTargetRef = new WeakReference(eventHandler.Target);
      
              mOpenHandler = (OpenEventHandler)Delegate.CreateDelegate(
                                 typeof(OpenEventHandler),null, eventHandler.Method);
      
              mHandler = Invoke;
              mUnregister = unregister;
          }
      
          public void Invoke(object sender, TE e)
          {
              T target = (T)mTargetRef.Target;
      
              if (target != null)
                  mOpenHandler.Invoke(target, sender, e);
              else if (mUnregister != null)
              {
                  mUnregister(mHandler);
                  mUnregister = null;
              }
          }
      
          public EventHandler<TE> Handler
          {
              get { return mHandler; }
          }
      
          public static implicit operator EventHandler<TE>(WeakEventHandler<T, TE> weh)
          {
              return weh.mHandler;
          }
      }
      
      public static class EventHandlerUtils
      {
          public static EventHandler<TE> MakeWeak<TE>(this EventHandler<TE> eventHandler, 
                                                          UnregisterCallback<TE> unregister)
              where TE : EventArgs
          {
              if (eventHandler == null)
                  throw new ArgumentNullException("eventHandler");
      
              if (eventHandler.Method.IsStatic || eventHandler.Target == null)
                  throw new ArgumentException("Only instance methods are supported.",
                                                  "eventHandler");
      
              var wehType = typeof(WeakEventHandler<,>).MakeGenericType(
                                eventHandler.Method.DeclaringType, typeof(TE));
      
              var wehConstructor = wehType.GetConstructor(new Type[] 
                                   { 
                                       typeof(EventHandler<TE>), typeof(UnregisterCallback<TE>) 
                                   });
      
              IWeakEventHandler<TE> weh = (IWeakEventHandler<TE>)wehConstructor.Invoke(
                                              new object[] { eventHandler, unregister });
      
              return weh.Handler;
          }
      }
      
      event EventHandler<RequestCloseEventArgs> RequestCloseDialog;
      
      public class RequestCloseEventArgs : EventArgs
      {
          public RequestCloseEventArgs(bool dialogResult)
          {
              this.DialogResult = dialogResult;
          }
      
          public bool DialogResult { get; private set; }
      }