wpf mvvm messagebox并等待ok / cancel

时间:2016-10-06 10:42:04

标签: c# wpf asynchronous mvvm messagebox

如何在另一个方法上继续冻结一个方法的执行,并在发生某些事件时返回原始方法。 (我基本上试图将丑陋的MessageBox.Show()替换为更多的MVVM版本)

请参阅以下示例:

private void ButtonClickRelayAction()
{
    DoMyMethod();
}


private void DoMyMethod()  <~~ I dont want to change this method if it can be helped
{
    Logic1();                                                     
    Logic2();                                                     
    var response1 = ShowMvvmMessageBox("Hello", "Please confirm");          <~ has to be run in the UI thread
    if (response1 == "Cancel")
        return;
    ContinueLogic3();                                             
    var response2 = ShowMvvmMessageBox("Hello", "Please confirm again");    <~ has to be run in the UI thread
    if (response2 == "Cancel")
        return;
    ContinueLogic4();                                             
}

private void ShowMvvmMessageBox(string question, string caption)
{
    interactionRequest = new InteractionRequest<IConfirmation>(), myMessage, title);
    interactionRequest.Raise(new Confirmation { Content = mainText, Title = title}, SomeAction<IConfirmation>);
    // This method ends before the user has clicked the button.
    // The SomeAction<IConfirmation> delegate is a callback when the user has clicked it, how do I handle it and continue execution of DoMyMethod from where it left off?
    // Everything i've tried freezes the UI thread..
}

提前致谢: - )

P.S。随意将我的逻辑分开并保持残酷。

3 个答案:

答案 0 :(得分:0)

我为你做了一个小例子,你可以看到如何解决你的问题。

我有以下ViewModel

internal class MainWindowViewModel
{
    private readonly DialogService dialogService;

    private ICommand dummyCommand;

    public MainWindowViewModel()
    {
        dialogService = new DialogService();
    }

    public ICommand DummyCommand
    {
        get { return dummyCommand ?? (dummyCommand = new RelayCommand<object>(p => Dummy())); }
    }

    private async void Dummy()
    {
        Logic1();
        await dialogService.ShowMvvmMessageBox("Question1?", "Q1?");
        Logic2();
        await dialogService.ShowMvvmMessageBox("Question2", "Q2");
        Logic3();
    }

    private void Logic1()
    {
        // So some logic here
    }

    private void Logic2()
    {
        // So some logic here
    }

    private void Logic3()
    {
        // So some logic here
    }
}

DialogService看起来像:

internal class DialogService 
{
    public async Task<bool> ShowMvvmMessageBox(string question, string caption)
    {
        bool res = await Task<bool>.Factory.StartNew(() =>
        {
            MessageBoxResult result = MessageBox.Show(question, caption, MessageBoxButton.YesNo);
            return result == MessageBoxResult.Yes;
        });
        return res;
    }
}

答案 1 :(得分:0)

我认为您可能正在寻找的是一个带有Ok-Cancel按钮的Dialogue Box(或等效物),在需要时显示它,然后处理它的返回值。正确的ViewModel实例我相信你已经使用DataContext绑定了正确的视图。

这个想法可能在代码中看起来像这样:

public partial class MainWindow : Window
    {

        MyViewModel vm = new MyViewModel();
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = vm;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {


            DXDialog d = new DXDialog("Information", DialogButtons.OkCancel,true);
            PropertyGrid p = new PropertyGrid() { DataContext = vm }; // Dialog view and Main view are both bound to the same viewmodel instance here.
            d.Content = p;
            d.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
            d.Owner = this;
            d.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
            var result = d.ShowDialog();
            if (result == true)
            {

                this.button1.Content = vm.Customer1;

            }
            else
            {
                // write the logic for "Cancel" button click. You can revert the Datacontext to the earlier value 
                //of the ViewModel by having saved its cloned object in this same method
            }


        }


    }

P.S:DXDialogue是一个DevExpress控件。你需要你的WPF等价物,我敢肯定。

答案 2 :(得分:0)

我这样做非常简单且符合MVVM:我在ViewModel和后面的View代码中定义事件,我显示MessageBox并设置EventArgs参数,以便ViewModel知道在View中按下了什么。我在View的DataContextChanged中附加了该事件的方法。另一种方法是使用完全分离的消息传递系统,但它的工作量要大得多。

Public Class GenericEventArgs(Of TEventData)
  Inherits EventArgs
  Public Sub New(Optional eventData As TEventData = Nothing)
    Me.EventData = eventData
  End Sub
  Public Property EventData As TEventData
End Class

Class MainWindow
  Private Sub Me_DataContextChanged(sender As Object, e As DependencyPropertyChangedEventArgs) Handles Me.DataContextChanged
      Dim mainWindowVM = DirectCast(DataContext, MainWindowViewModel)
      AddHandler mainWindowVM.SavingChanges, AddressOf MainWindowViewModel_SavingChanges
  End Sub
  Private Sub MainWindowViewModel_SavingChanges(sender As Object, e As GenericEventArgs(Of Boolean?))
    If MessageBox.Show("Save changes?",
                       "Document was changed",
                       MessageBoxButton.YesNo,
                       MessageBoxImage.Exclamation) = MessageBoxResult.Yes Then
      e.EventData = True
    Else
      e.EventData = False
    End If
  End Sub
End Class

Class MainWindowViewModel
  Public Event SavingChanges As EventHandler(Of GenericEventArgs(Of Boolean?))
  Public Sub SaveChanges()
    Dim e As New GenericEventArgs(Of Boolean?)
    RaiseEvent SavingChanges(Me, e)
    If e.EventData = True Then
      'User want to save changes
    Else
      'User dont want to save changes
    End If
  End Sub
End Class