UI 디스패처를 ViewModel로 전달하는 방법
View에 속하는 Dispatcher에 액세스할 수 있어야 하며 ViewModel에 전달해야 합니다.그러나 View는 View Model에 대해 아무것도 모르면 안 됩니다. 그렇다면 View Model은 어떻게 통과해야 합니까?인터페이스를 도입하거나 해당 인터페이스를 인스턴스에 전달하는 대신 View에서 작성되는 글로벌 디스패처 싱글톤을 작성하시겠습니까?MVVM 애플리케이션 및 프레임워크에서 이 문제를 해결하려면 어떻게 해야 합니까?
수 있기 에 "View Models"만 수 .Dispatcher.CurrentView Model view view view 。
인터페이스 IContext를 사용하여 디스패처를 추상화했습니다.
public interface IContext
{
bool IsSynchronized { get; }
void Invoke(Action action);
void BeginInvoke(Action action);
}
이를 통해 View Model을 보다 쉽게 유닛 테스트할 수 있다는 장점이 있습니다.
MEF(Managed Extensibility Framework)의 View Model입니다.을 하다MEF를 사용하다
업데이트(댓글의 페이스트빈 링크 예):
public sealed class WpfContext : IContext
{
private readonly Dispatcher _dispatcher;
public bool IsSynchronized
{
get
{
return this._dispatcher.Thread == Thread.CurrentThread;
}
}
public WpfContext() : this(Dispatcher.CurrentDispatcher)
{
}
public WpfContext(Dispatcher dispatcher)
{
Debug.Assert(dispatcher != null);
this._dispatcher = dispatcher;
}
public void Invoke(Action action)
{
Debug.Assert(action != null);
this._dispatcher.Invoke(action);
}
public void BeginInvoke(Action action)
{
Debug.Assert(action != null);
this._dispatcher.BeginInvoke(action);
}
}
왜 사용하지 않는가?
System.Windows.Application.Current.Dispatcher.Invoke(
(Action)(() => {ObservableCollectionMemeberOfVM.Add("xx"); } ));
GUI 디스패처를 참조하는 것이 아니라
실제로 디스패처가 필요하지 않을 수도 있습니다.뷰 모델의 속성을 뷰 내의 GUI 요소에 바인드하면 WPF 바인딩 메커니즘은 디스패처를 사용하여 GUI 업데이트를 자동으로 GUI 스레드에 마셜링합니다.
편집:
이 편집은 Issak Savo의 코멘트에 대한 응답입니다.
속성에 대한 바인딩을 처리하는 Microsoft 코드에는 다음 코드가 있습니다.
if (Dispatcher.Thread == Thread.CurrentThread)
{
PW.OnPropertyChangedAtLevel(level);
}
else
{
// otherwise invoke an operation to do the work on the right context
SetTransferIsPending(true);
Dispatcher.BeginInvoke(
DispatcherPriority.DataBind,
new DispatcherOperationCallback(ScheduleTransferOperation),
new object[]{o, propName});
}
이 코드는 스레드 UI 스레드에 대한 UI 업데이트를 모두 수행하므로 다른 스레드에서 바인딩의 일부를 사용하여 속성을 업데이트하더라도 WPF는 콜을 UI 스레드에 자동으로 시리얼화합니다.
View Model이 현재 디스패처를 멤버로 저장하도록 합니다.
ViewModel이 뷰에 의해 작성된 경우 작성 시 현재 디스패처가 뷰의 디스패처가 됩니다.
class MyViewModel
{
readonly Dispatcher _dispatcher;
public MyViewModel()
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
}
에는 MVVM Light 5.2가 되어 .DispatcherHelper을 in in in in GalaSoft.MvvmLight.Threading에 됩니다.CheckBeginInvokeOnUI()UI를 사용하다ViewModel에서 UI 요소가 바인딩된 VM 속성에 영향을 미치는 일부 작업자 스레드를 실행하는 경우 매우 유용합니다.
DispatcherHelper하려면 을 호출해야 .DispatcherHelper.Initialize()를 들어, 「어플리케이션의 라이프 사이클」의 :App_Startup그런 다음 다음 호출을 사용하여 임의의 위임자(또는 람다)를 실행할 수 있습니다.
DispatcherHelper.CheckBeginInvokeOnUI(
() =>
{
//Your code here
});
는 " " " 에서되어 있습니다.GalaSoft.MvvmLight.Platform이 라이브러리는 NuGet을 통해 추가할 때 기본적으로 참조되지 않습니다.lib로 하다
또 다른 일반적인 패턴(현재 프레임워크에서 많이 사용되고 있음)은 Synchronization Context입니다.
이를 통해 동기 및 비동기적으로 디스패치할 수 있습니다.현재 스레드에 현재 Synchronization Context를 설정할 수도 있습니다.즉, 쉽게 조롱됩니다.Dispatcher Synchronization Context는 WPF 앱에서 사용됩니다.Synchronization Context의 기타 구현은 WCF 및 WF4에서 사용됩니다.
WPF 버전 4.5부터는 Current Dispatcher를 사용할 수 있습니다.
Dispatcher.CurrentDispatcher.Invoke(() =>
{
// Do GUI related operations here
}, DispatcherPriority.Normal);
다른 스레드 내의 바인드된 컬렉션을 수정하기 위해 디스패처만 필요한 경우 다음 URL에서 Synchronization Context Collection을 참조하십시오.
정상적으로 동작하지만 SynchronizationContextCollection 속성이 있는 View Models를 ASP와 함께 사용하는 경우에만 문제가 발견되었습니다.NET 동기 콘텍스트는 간단하게 조작할 수 있습니다.
HTH 샘
안녕 아마도 너의 첫 게시물로부터 8개월이 지났기 때문에 내가 너무 늦은 것 같아...Silverlight mvm 어플리케이션에서도 같은 프로블이 있었어요.이렇게 해결책을 찾았습니다.내가 가지고 있는 각 모델과 뷰 모델에는 컨트롤러라는 클래스도 있습니다.이런 거죠.
public class MainView : UserControl // (because it is a silverlight user controll)
public class MainViewModel
public class MainController
MainController는 모델과 뷰 모델 간의 명령 및 연결을 담당합니다.생성자에서 뷰와 뷰 모델을 설치하고 뷰의 데이터콘텍스트를 뷰 모델로 설정합니다.
mMainView = new MainView();
mMainViewModel = new MainViewModel();
mMainView.DataContext = mMainViewModel;
//(내 명명 규칙에는 멤버 변수의 접두사 m이 있습니다)
MainView 타입의 공유 재산도 가지고 있습니다.이런 거죠.
public MainView View { get { return mMainView; } }
(이 mMainView는 공용 속성의 로컬 변수입니다.)
이제 난 끝났어이런 식으로 내 UI를 위해 내 디스패처를 쓰면 되는데...
mMainView.Dispatcher.BeginInvoke(
() => MessageBox.Show(mSpWeb.CurrentUser.LoginName));
(이 예에서는 컨트롤러에 sharepoint 2010 로그인명을 취득하도록 요청하고 있습니다만, 필요에 따라서 취득할 수 있습니다.)
거의 완료했습니다.또한 앱에서 루트 비주얼을 정의해야 합니다.xaml은 다음과 같습니다.
var mainController = new MainController();
RootVisual = mainController.View;
이게 내 지원서에 도움을 줬어. 아마 너도 도움이 될 거야.
UI 디스패처를 ViewModel에 전달할 필요가 없습니다.UI 디스패처는 현재 애플리케이션 싱글톤에서 사용할 수 있습니다.
App.Current.MainWindow.Dispatcher
이렇게 하면 ViewModel이 View에 종속됩니다.신청 내용에 따라서는, 그것은 문제가 없을 수도 있습니다.
WPF 및 Windows 스토어 어플리케이션의 경우:-
System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => {ObservableCollectionMemeberOfVM.Add("xx"); } ));
GUI 디스패처를 참조하는 것은 올바른 방법이 아닙니다.
Windows Phone 8 어플리케이션의 경우 등)이 동작하지 않는 경우는, 다음을 사용해 주세요.
Deployment.Current.Dispatcher
uNhAdd를 사용하는 경우비동기적인 행동을 쉽게 할 수 있습니다. 여기를 보세요.
그리고 Castle Windsor에서 작동하려면 약간의 수정이 필요하다고 생각합니다(uNhAddsIns 제외).
다른 (가장 간단한) 방법을 찾았습니다.
Dispatcher에서 호출해야 하는 모델 액션을 뷰에 추가합니다.
public class MyViewModel
{
public Action<Action> CallWithDispatcher;
public void SomeMultithreadMethod()
{
if(CallWithDispatcher != null)
CallWithDispatcher(() => DoSomethingMetod(SomeParameters));
}
}
뷰 생성자에 다음 작업 핸들러를 추가합니다.
public View()
{
var model = new MyViewModel();
DataContext = model;
InitializeComponent();
// Here
model.CallWithDispatcher += act => _taskbarIcon.Dispatcher
.BeginInvoke(DispatcherPriority.Normal, act) ;
}
이제 테스트에 문제가 없고 구현도 간단합니다.사이트에 추가했습니다.
응용 프로그램 디스패처에 액세스할 수 있는 경우 디스패처를 통과할 필요가 없습니다.
Dispatcher dis = Application.Current.Dispatcher
내 WPF 프로젝트 중 일부는 내가 같은 상황에 직면했었다.MainViewModel(싱글톤 인스턴스)에서는 CreateInstance() 스태틱메서드로 디스패처가 취득되었습니다.또한 View에서 생성 인스턴스가 호출되어 Dispatcher를 통과할 수 있습니다.ViewModel 테스트모듈은 CreateInstance() 파라미터 없이 호출합니다.
그러나 복잡한 멀티스레드 시나리오에서는 현재 윈도우의 적절한 디스패처를 얻기 위해 View 측에서 인터페이스를 구현하는 것이 항상 좋습니다.
이 토론에 조금 늦었을지도 모르지만, https://msdn.microsoft.com/en-us/magazine/dn605875.aspx에서 좋은 기사를 하나 찾았습니다.
1개의 단락이 있다
또한 View 계층 외부의 모든 코드(즉, View Model 및 Model 계층, 서비스 등)는 특정 UI 플랫폼에 연결된 유형에 의존해서는 안 됩니다.Dispatcher(WPF/Xamarin/Windows Phone/Silverlight), CoreDispatcher(Windows Store) 또는 ISynchronize를 직접 사용하는 경우(Windows Forms)를 호출하는 것은 좋지 않습니다.(Synchronization Context는 약간 낫지만 거의 낫지 않습니다.)예를 들어 인터넷에는 비동기식 작업을 하고 디스패처를 사용하여 UI를 업데이트하는 코드가 많이 있습니다.비동기식 작업을 대기하고 디스패처를 사용하지 않고 UI를 업데이트하는 것이 보다 휴대성이 높고 번거롭지 않은 솔루션입니다.
비동기/대기 기능을 올바르게 사용할 수 있다면 이는 문제가 되지 않는다고 가정합니다.
언급URL : https://stackoverflow.com/questions/2354438/how-to-pass-the-ui-dispatcher-to-the-viewmodel
'source' 카테고리의 다른 글
| WPF 엔트리 포인트 교환 (0) | 2023.04.12 |
|---|---|
| 엑셀의 서브스트링 (0) | 2023.04.12 |
| 셀이 변경될 때마다 Excel VBA가 매크로를 자동으로 실행 (0) | 2023.04.12 |
| WPF(C# 또는 vb.net)에서 응용 프로그램 실행 파일의 위치를 찾을 수 있습니까? (0) | 2023.04.12 |
| Python에서 datetime 객체를 인식(순진하지 않음)시키는 방법 (0) | 2023.04.12 |