Gần đây tôi gặp vấn đề trong việc tạo các hộp thoại thêm và chỉnh sửa cho ứng dụng wpf của mình.
Tất cả tôi muốn làm trong mã của tôi là một cái gì đó như thế này. (Tôi chủ yếu sử dụng phương pháp tiếp cận đầu tiên của viewmodel với mvvm)
ViewModel gọi cửa sổ hộp thoại:
var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
// Do anything with the dialog result
Làm thế nào nó hoạt động?
Đầu tiên, tôi tạo một dịch vụ hộp thoại:
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
là một cửa sổ đặc biệt nhưng đơn giản. Tôi cần nó để giữ nội dung của tôi:
<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>
Một vấn đề với các hộp thoại trong wpf là dialogresult = true
chỉ có thể đạt được trong mã. Đó là lý do tại sao tôi tạo ra một giao diện để tôi dialogviewmodel
thực hiện nó.
public class RequestCloseDialogEventArgs : EventArgs
{
public bool DialogResult { get; set; }
public RequestCloseDialogEventArgs(bool dialogresult)
{
this.DialogResult = dialogresult;
}
}
public interface IDialogResultVMHelper
{
event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}
Bất cứ khi nào ViewModel của tôi nghĩ rằng đã đến lúc dialogresult = true
, hãy nâng cao sự kiện này.
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;
}
}
Bây giờ ít nhất tôi phải tạo một DataTemplate
tệp trong tài nguyên của mình ( app.xaml
hoặc một cái gì đó):
<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
<DialogView:EditOrNewAuswahlItem/>
</DataTemplate>
Vâng đó là tất cả, bây giờ tôi có thể gọi các hộp thoại từ chế độ xem của mình:
var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
Bây giờ câu hỏi của tôi, bạn có thấy bất kỳ vấn đề với giải pháp này?
Chỉnh sửa: cho đầy đủ. ViewModel nên triển khai IDialogResultVMHelper
và sau đó nó có thể nâng cao nó trong một OkCommand
hoặc một cái gì đó như thế này:
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: Tôi đã sử dụng mã từ đây để làm cho đăng ký EventHandler của mình yếu đi:
http://diditwith.net/2007/03/23/SolveThePro HiệuWithEventsWeakEventHandlers.aspx
(Trang web không còn tồn tại, WebArchive Mirror )
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;
}
}