MVVM을 사용하는 wpf의 대화상자에 대한 바람직한 방법 또는 나쁜 방법?
최근에 wpf 앱의 추가 및 편집 대화상자를 만드는 데 문제가 있었습니다.
코드로 하고 싶은 것은 이것뿐입니다.(주로 mvvm에서는 뷰모델 우선접근법을 사용합니다)
대화창을 호출하는 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;
}
Model이 Model이 필요한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;
}
}
나는 제제 a a a a a를 .DataTemplate
리소스 파일)에서app.xaml
[ ] :
<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
<DialogView:EditOrNewAuswahlItem/>
</DataTemplate>
이것으로 뷰모델에서 다이얼로그를 호출할 수 있게 되었습니다.
var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
이제 질문입니다. 이 솔루션에 문제가 있다고 생각하십니까?
편집: 완전성을 확보합니다.은 View Model을 구현해야 .IDialogResultVMHelper
하면 1번으로 수 요.OkCommand
것: " " or or or or or or "
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: 여기서부터의 코드를 사용하여, Event Handler 의 등록을 약하게 했습니다.
http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspxhttpdiditwith.net/2007/03/23/.aspx
(웹사이트는 더 이상 존재하지 않습니다, 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;
}
}
이것은 좋은 방법이고 나는 예전에 비슷한 방법을 사용했다.화이팅!
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
), 「」, 「」(」, 「Dialogs」, 「Dialogs」, 「Dialogs」, 「Dialogs」, 「Dialogs」의 것이 됩니다.RequestClose
및 윈도 할 수 몇
팝업 메시지 상자뿐만 아니라 대화창에 대해서도 언급하고 있다면 아래의 접근 방식을 고려해 주십시오.요점은 다음과 같습니다.
- 를
Module Controller
의ViewModel
(일부러) - ★★★
Module Controller
에는 (결과를 반환하지 않고 작성만 하고) 대화창을 작성하는 퍼블릭/내부 방법이 있습니다. 에서 .ViewModel
나는 다음과 같이 쓰고 있다.controller.OpenDialogEntity(bla, bla...)
- 각 대화창은 Weak Events를 통해 결과를 알립니다(확인, 저장, 취소 등).PRISM을 사용하면 이 Event Aggregator를 사용하여 알림을 게시할 수 있습니다.
- 대화 결과를 처리하기 위해 알림 구독(PRISM의 경우 Weak Events와 Event Aggregator)을 사용하고 있습니다.이러한 통지에 대한 의존성을 줄이려면 표준 통지에 독립 클래스를 사용하십시오.
장점:
- 코드를 줄이다.인터페이스를 사용하는 것은 상관없지만, 인터페이스나 추상화 레이어를 과도하게 사용하는 것이 도움이 되기보다 더 많은 문제를 일으키는 프로젝트를 너무 많이 봐왔습니다.
- 대화창 열기
Module Controller
는 강력한 참조를 피하기 위한 간단한 방법으로, 테스트에 목업을 사용할 수 있습니다. - 약한 이벤트를 통한 알림은 잠재적인 메모리 누전 수를 줄입니다.
단점:
- 핸들러 내의 다른 알림과 필요한 알림을 구별하기가 쉽지 않습니다.두 가지 솔루션:
- 대화창을 열 때 고유 토큰을 전송하고 구독에서 해당 토큰을 확인합니다.
- 범용 알림 클래스 사용
<T>
어디에T
는 엔티티의 열거형입니다(간단히 말하면 ViewModel 유형으로 할 수 있습니다).
- 프로젝트에는 알림 클래스를 사용하여 중복을 방지하는 데 대한 동의서가 있어야 합니다.
- 대규모 프로젝트에서는
Module Controller
창 작성 방법에 시달릴 수 있습니다.이 경우 여러 모듈로 분할하는 것이 좋습니다.
P.S. 저는 이 접근방식을 꽤 오랫동안 사용해 왔고, 필요한 경우 코멘트로 적격성을 옹호하고 몇 가지 예를 제공할 준비가 되어 있습니다.
언급URL : https://stackoverflow.com/questions/3801681/good-or-bad-practice-for-dialogs-in-wpf-with-mvvm
'source' 카테고리의 다른 글
콘텐츠에 대한 WPF 컨트롤 크기 (0) | 2023.04.14 |
---|---|
Nullable 열을 NOT NULL(기본값)로 변경합니다. (0) | 2023.04.14 |
Excel에서 번다운 차트를 작성하려면 어떻게 해야 하나요? (0) | 2023.04.14 |
bash 스크립트를 사용하여 모든 git 브랜치를 반복하는 방법 (0) | 2023.04.14 |
취소선 텍스트를 사용하여 UILabel을 작성하려면 어떻게 해야 합니까? (0) | 2023.04.14 |