问题描述
我最近作了创建添加和编辑对话框我WPF应用程序的问题。
我只想在我的code做的就是这样的事情。 (我主要使用与MVVM视图模型第一种方法)
视图模型这就要求一个对话窗口:
VAR的结果= this.uiDialogService.ShowDialog(Dialogwindow名称在这儿,dialogwindowVM); ...做的对话框结果什么...
它是如何工作的?
首先,我创建了一个对话框服务:
公共接口IUIWindowDialogService
{
布尔?的ShowDialog(字符串名称,对象的datacontext);
}公共类WpfUIWindowDialogService:IUIWindowDialogService
{
公共BOOL?的ShowDialog(字符串名称,对象的datacontext)
{
VAR赢=新WindowDialog();
win.Title =称号;
win.DataContext = DataContext的; 返回win.ShowDialog();
}}
WindowDialog
是一个特殊而简单的窗口。我需要它来保存我的内容:
<窗口x:类=WindowDialog
的xmlns =http://schemas.microsoft.com/winfx/2006/xaml/$p$psentation
标题=WindowDialog
WindowStyle =SingleBorderWindow
WindowStartupLocation =CenterOwnerSizeToContent =WidthAndHeight>
<内容presenter X:NAME =对话框presenterCONTENT ={结合}> < /内容presenter>
< /窗GT;
在WPF对话的一个问题是的DialogResult = TRUE
。这只能在code来实现。这就是为什么我创造了我的 dialogviewmodel
来实现一个接口。
公共类RequestCloseDialogEventArgs:EventArgs的
{
公共RequestCloseDialogEventArgs(布尔的DialogResult)
{
this.DialogResult =的DialogResult;
} 公共BOOL的DialogResult
{
得到;组;
}
}公共接口IDialogResultVMHelper
{
事件的EventHandler< RequestCloseDialogEventArgs> RequestCloseDialog;
}
每当我的视图模型认为它的时间的DialogResult = true,则引发此事件。
公共部分类DialogWindow:窗口
{
// Merken WENN窗口geschlossen wurde,damit kein的DialogResult梅尔gesetzt wird
私人布尔_isClosed = FALSE; 公共DialogWindow()
{
的InitializeComponent();
this.Dialog presenter.DataContextChanged + =对话框presenterDataContextChanged;
this.Closed + = DialogWindowClosed;
} 无效DialogWindowClosed(对象发件人,EventArgs的发送)
{
this._isClosed = TRUE;
} 私人无效对话presenterDataContextChanged(对象发件人,DependencyPropertyChangedEventArgs E)
{
变种D = e.NewValue为IDialogResultVMHelper; 如果(D == NULL)
返回; d.RequestCloseDialog + =新的EventHandler< RequestCloseDialogEventArgs>(DialogResultTrueEvent).MakeWeak(EH = GT; d.RequestCloseDialog - = EH); ;
} 私人无效DialogResultTrueEvent(对象发件人,EventArgs的RequestCloseDialogEventArgs)
{
//重要事项damit献给EIN geschlossenes窗口kein的DialogResult梅尔gesetzt wird
// GCräumt窗口irgendwann WEG UND durch MakeWeak fliegt ES奥赫BEIM IDialogResultVMHelper的RAU
如果(_isClosed)回报; this.DialogResult = eventargs.DialogResult;
}
现在我至少要创建一个的DataTemplate
在我的资源文件(的App.xaml
或东西):
<数据类型的DataTemplate ={X:类型DialogViewModel:EditOrNewAuswahlItemVM}>
< DialogView:EditOrNewAuswahlItem />
< / DataTemplate中>
好了多数民众赞成,我现在可以叫对话从我的ViewModels:
VAR的结果= this.uiDialogService.ShowDialog(Dialogwindow名称在这儿,dialogwindowVM);
现在我的问题,你看到的任何问题,这个解决方案?
编辑:完整。该视图模型应该实现IDialogResultVMHelper,然后可以在OkCommand或像这样
中提出来 公共类MyViewmodel:IDialogResultVMHelper
{
私人只读懒< DelegateCommand> _okCommand; 公共MyViewmodel()
{
this._okCommand =新懒人< DelegateCommand>(()=>新建DelegateCommand(()=> InvokeRequestCloseDialog(新RequestCloseDialogEventArgs(真)),()=> YourConditionsGoesHere = TRUE));
} 公众的ICommand OkCommand
{
{返回this._okCommand.Value; }
} 公共事件的EventHandler< RequestCloseDialogEventArgs> RequestCloseDialog; 私人无效InvokeRequestCloseDialog(RequestCloseDialogEventArgs E)
{
VAR处理器= RequestCloseDialog;
如果(处理!= NULL)
处理程序(这一点,E);
}
}
编辑2:我用的是code从http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx让我的事件处理程序注册薄弱。
公共委托无效UnregisterCallback<&TE GT;(事件处理程序和LT; TE>事件处理程序)
其中,TE:EventArgs的;公共接口IWeakEventHandler<&TE GT;
其中,TE:EventArgs的
{
事件处理<&TE GT;处理程序{搞定; }
}公共类WeakEventHandler< T,TE> :IWeakEventHandler<&TE GT;
其中T:类
其中,TE:EventArgs的
{
私人委托无效OpenEventHandler(T @this,对象发件人,TE E); 私人只读了WeakReference mTargetRef;
私人只读OpenEventHandler mOpenHandler;
私人只读事件处理程序和LT; TE> mHandler;
私人UnregisterCallback<&TE GT; mUnregister; 公共WeakEventHandler(事件处理程序和LT; TE>事件处理程序,UnregisterCallback<&TE GT;注销)
{
mTargetRef =新的WeakReference(eventHandler.Target); mOpenHandler =(OpenEventHandler)Delegate.CreateDelegate(typeof运算(OpenEventHandler),空,eventHandler.Method); mHandler =调用;
mUnregister =注销;
} 公共无效调用(对象发件人,TE E)
{
t定向=(T)mTargetRef.Target; 如果(目标!= NULL)
mOpenHandler.Invoke(目标,发件人,E);
否则,如果(mUnregister!= NULL)
{
mUnregister(mHandler);
mUnregister = NULL;
}
} 公共事件处理程序和LT; TE>处理器
{
{返回mHandler; }
} 公共静态隐运营商的EventHandler<&TE GT;(WeakEventHandler< T,TE> WEH)
{
返回weh.mHandler;
}
}公共静态类EventHandlerUtils
{
公共静态事件处理程序和LT; TE> MakeWeak<&TE GT;(此事件处理程序和LT; TE>事件处理程序,UnregisterCallback<&TE GT;注销)
其中,TE:EventArgs的
{
如果(事件处理程序== NULL)
抛出新的ArgumentNullException(事件处理程序); 如果(eventHandler.Method.IsStatic || eventHandler.Target == NULL)
抛出新的ArgumentException(只有实例方法都支持。,事件处理程序); VAR wehType = typeof运算(WeakEventHandler<,>)。MakeGenericType(eventHandler.Method.DeclaringType的typeof(TE)); VAR wehConstructor = wehType.GetConstructor(新类型[] {typeof运算(事件处理程序和LT; TE>)的typeof(UnregisterCallback<&TE GT;)}); IWeakEventHandler<&TE GT; WEH =(IWeakEventHandler<&TE GT;)wehConstructor.Invoke(新的对象[] {事件处理程序,注销}); 返回weh.Handler;
}
}
这是一个很好的方法,我在过去使用类似的。加油!
一个次要的事情我肯定会做的是使事件得到当你需要在DialogResult的设置假的布尔。
事件事件处理程序和LT; RequestCloseEventArgs> RequestCloseDialog;
和EventArgs类:
公共类RequestCloseEventArgs:EventArgs的
{
公共RequestCloseEventArgs(布尔的DialogResult)
{
this.DialogResult =的DialogResult;
} 公共BOOL的DialogResult {搞定;私人集; }
}
I lately had the problem of creating add and edit dialogs for my wpf app.
All I want to do in my code was something like this. (I mostly use viewmodel first approach with mvvm)
ViewModel which calls a dialog window:
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
... do anything with the dialog result...
How does it work?
First, I created a dialog service:
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
is a special but simple window. I need it to hold my content:
<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>
A problem with dialogs in wpf is the dialogresult = true
. This can only be achieved in code. That's why I created an interface for my dialogviewmodel
to implement.
public class RequestCloseDialogEventArgs : EventArgs
{
public RequestCloseDialogEventArgs(bool dialogresult)
{
this.DialogResult = dialogresult;
}
public bool DialogResult
{
get; set;
}
}
public interface IDialogResultVMHelper
{
event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}
Whenever my viewmodel think its time for dialogresult=true, then raise this event.
public partial class DialogWindow : Window
{
//Merken wenn Window geschlossen wurde, damit kein DialogResult mehr gesetzt wird
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)
{
//Wichtig damit für ein geschlossenes Window kein DialogResult mehr gesetzt wird
//GC räumt Window irgendwann weg und durch MakeWeak fliegt es auch beim IDialogResultVMHelper raus
if(_isClosed) return;
this.DialogResult = eventargs.DialogResult;
}
Now at least I have to create a DataTemplate
in my resource file(app.xaml
or something):
<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
<DialogView:EditOrNewAuswahlItem/>
</DataTemplate>
Well thats all, I can now call dialogs from my viewmodels:
var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);
Now my question, do you see any problems with this solution?
Edit: for completeness. the viewmodel should implement IDialogResultVMHelper and then can raise it within a OkCommand or something like this
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);
}
}
EDIT 2: i use the code from http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx for making my Eventhandler register weak.
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;
}
}
This is a good approach and I used similar ones in the past. Go for it!
One minor thing I'd definitely do is make the event receive a boolean for when you need to set "false" in the DialogResult.
event EventHandler<RequestCloseEventArgs> RequestCloseDialog;
and the EventArgs class:
public class RequestCloseEventArgs : EventArgs
{
public RequestCloseEventArgs(bool dialogResult)
{
this.DialogResult = dialogResult;
}
public bool DialogResult { get; private set; }
}
这篇关于对于对话框是好还是不好的做法在WPF与MVVM?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!