[英]MVVM showDialog with owner and close when background worker finishes
我只是想了解WPF中的MVVM模式(當前沒有任何框架)。
場景:
我有一個主窗口,單擊與視圖模型中的某些命令綁定的“開始工作”按鈕。 進度對話框應使用“取消”按鈕打開,它應顯示在所有者窗口的中央(因此我需要通過所有者),按取消,然后在后台工作程序上調用“ CancelAsync”方法。
MVVM的原理是,視圖模型永遠不應該對視圖一無所知,在我的情況下,我違反了該規則。
后台代碼(無MVVM)解決方案:
主窗口部分:
private void Button_Click(object sender, RoutedEventArgs e)
{
backgroundWorker.RunWorkerAsync();
progressWindow = new ProgressWindow(backgroundWorker);
progressWindow.Owner = this;
progressWindow.ShowDialog();
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressWindow.Close();
}
進度窗口部分:
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
backgroundWorker.CancelAsync();
}
我試圖將此代碼轉換為MVVM(這是錯誤的)
public class MainViewModel
{
public ICommand DoSomething { get; }
private BackgroundWorker backgroundWorker;
private PleaseWaitView pleaseWaitView;
public MainViewModel()
{
backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true };
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
var pleaseWaitViewModel = new PleaseWaitViewModel(backgroundWorker);
pleaseWaitView = new PleaseWaitView();
pleaseWaitView.Owner = Application.Current.MainWindow;
pleaseWaitView.DataContext = pleaseWaitViewModel;
DoSomething = new ActionCommand<object>(DoSomethingImpl);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pleaseWaitView.Close();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Some work
Thread.Sleep(5000);
}
private void DoSomethingImpl(object parameter)
{
pleaseWaitView.ShowDialog();
}
}
如何解決呢? 我花了20分鍾的時間完成了我想做的代碼隱藏工作,我想嘗試MVVM模式,花了幾個小時才能解決簡單的問題。
我當時在看一些使用EventAggregator的解決方案,但這需要使用Prism,Caliburn.Micro之類的框架。 這樣我就可以在VM和View之間進行某種通信。
您可以將接口傳遞給MainViewModel,其中包含所需的方法
interface IMainView
{
void Init(PleaseWaitViewModel viewModel);
void ShowDialog();
void Close();
}
public class MainViewModel
{
private IMainView _view;
public MainViewModel(IMainView view)
{
_view = view;
backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true };
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
BackgroundWorker_RunWorkerCompleted;
var pleaseWaitViewModel = new PleaseWaitViewModel(backgroundWorker);
_view.Init(pleaseWaitViewModel);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_view.Close();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Some work
Thread.Sleep(5000);
}
private void DoSomethingImpl(object parameter)
{
_view.ShowDialog();
}
}
信使方式
public class PersonsViewModel
{
private RelayCommand _addPersonCommand = null;
public RelayCommand AddPersonCommand
{
get
{
return _addPersonCommand ?? (_addPersonCommand = new RelayCommand(
() =>
{
Action<Person> callback = (person) =>
{
_persons.Add(person);
RaisePropertyChanged("Persons");
};
Messenger.Default.Send<NotificationMessageAction<Person>>(new NotificationMessageAction<Person>(this, new Person(), "myNotification", callback), this);
}));
}
}
}
private PersonsViewModel _viewModel = null;
public PersonsView()
{
InitializeComponent();
DataContext = _viewModel = new PersonsViewModel();
Messenger.Default.Register<NotificationMessageAction<Person>>(this, _viewModel, message =>
{
if(message.Notification == "myNotification")
{
Person person = (Person)message.Target;
Action<Person> callback = message.Execute;
ModalView view = new ModalView(person);
if(true == view.ShowDialog())
{
callback.Invoke(view.Person);
}
}
});
}
視圖模型方法的動作屬性
1)在viewmodel上添加action屬性
2)將其連接到后面的視圖代碼中
3)在需要的地方在viewmodel邏輯中調用動作
using System;
using System.Windows;
using System.Windows.Input;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Wire up CancelAction in the View
var windowToClose = new Window();
var castedContext = (ViewModel) DataContext;
castedContext.CancelAction = () => windowToClose.Close();
}
}
public class ViewModel
{
private ICommand _doSomethingCommand;
public Action CancelAction { get; set; }
public ICommand DoSomethingCommand
{
get
{
if (_doSomethingCommand != null)
return _doSomethingCommand;
_doSomethingCommand = new MyCommandImplementation(() =>
{
// Perform Logic
// If need to cancel - invoke cancel action
CancelAction.Invoke();
});
return _doSomethingCommand;
}
}
}
// Stubbed out for the sake of complete code
public class MyCommandImplementation : ICommand
{
public MyCommandImplementation(Action action)
{
throw new NotImplementedException();
}
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
throw new NotImplementedException();
}
public event EventHandler CanExecuteChanged;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.