用MVVM与wpf对话的好习惯或不好的做法?
我最近遇到了为我的wpf应用程序创建添加和编辑对话框的问题。
我想在我的代码中做的就是这样的。 (我主要使用mvvm的viewmodel第一种方法)
调用对话窗口的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>
wpf中的对话框的问题是dialogresult = true
只能在代码中实现。 这就是为什么我为我的dialogviewmodel
创建一个接口来实现它。
public class RequestCloseDialogEventArgs : EventArgs
{
public bool DialogResult { get; set; }
public RequestCloseDialogEventArgs(bool dialogresult)
{
this.DialogResult = dialogresult;
}
}
public interface IDialogResultVMHelper
{
event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}
每当我的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;
}
}
现在至少我必须在我的资源文件( app.xaml
或其他)中创建一个DataTemplate
:
<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
<DialogView:EditOrNewAuswahlItem/>
</DataTemplate>
那么所有,我现在可以从我的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);
}
}
编辑2:我用这里的代码使我的EventHandler寄存器变弱:
http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx
(网站不再存在,WebArchive镜像)
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;
}
}
这是一个很好的方法,过去我也使用过类似的方法。 去吧!
我确实要做的一件小事是让事件在DialogResult中需要设置“false”时接收一个布尔值。
event EventHandler<RequestCloseEventArgs> RequestCloseDialog;
和EventArgs类:
public class RequestCloseEventArgs : EventArgs
{
public RequestCloseEventArgs(bool dialogResult)
{
this.DialogResult = dialogResult;
}
public bool DialogResult { get; private set; }
}
我几个月来一直在使用几乎相同的方法,我对此感到非常满意(即,我还没有感受到完全重写它的冲动......)
在我的实现中,我使用了一个IDialogViewModel
,它公开了诸如标题, IDialogViewModel
按钮的显示(为了在所有对话中保持一致的服从),一个RequestClose
事件以及其他一些能够控制窗口的事情大小和行为
如果您在谈论对话窗口而不仅仅是弹出式消息框,请考虑下面的方法。 关键点是:
Module Controller
的引用传递给每个ViewModel
的构造函数(可以使用注入)。 Module Controller
具有创建对话窗口的公共/内部方法(只需创建,而不返回结果)。 因此,在ViewModel
打开一个对话窗口我写: controller.OpenDialogEntity(bla, bla...)
优点:
Module Controller
打开对话窗口是避免强引用的简单方法,并且仍允许使用模型进行测试。 缺点:
<T>
其中T
是实体的枚举(或者为了简单起见,它可以是ViewModel的类型)。 Module Controller
可能会被创建窗口的方法所淹没。 在这种情况下,最好将它分成几个模块。 PS我现在一直在使用这种方法很长一段时间,并准备捍卫其评论的资格,并在必要时提供一些示例。
链接地址: http://www.djcxy.com/p/56107.html