C# 使用MVVM在wpf中进行对话的好做法还是坏做法?
我最近遇到了为我的wpf应用程序创建添加和编辑对话框的问题 我想在代码中做的就是这样的事情。(我主要在mvvm中使用viewmodel-first方法) 调用对话框窗口的ViewModel: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
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…)
- 更少的代码。我不介意使用接口,但我见过太多项目过度使用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; } }