簡體   English   中英

MVVM showDialog與所有者並在后台工作人員完成時關閉

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM