简体   繁体   English

如何在 WPF MVVM 应用程序中添加是-否确认对话框?

[英]How to add a yes-no confirmation dialog in a WPF MVVM application?

I am developping a .net desktop WPF app in MVVM pattern using Visual Studio.我正在使用 Visual Studio 以 MVVM 模式开发一个 .net 桌面 WPF 应用程序。 I want to add confirmation dialog and bind "yes" or "no" according to the user click.我想添加确认对话框并根据用户点击绑定“是”或“否”。 I made some research but solutions offered either is not appropriate for MVVM pattern or requires adding a lot of external packages which I dont want to.我做了一些研究,但提供的解决方案要么不适合 MVVM 模式,要么需要添加很多我不想添加的外部包。 Could anyone help me to find a proper solution that solves my problem?谁能帮我找到解决我问题的合适解决方案?

I would like to suggest a solution that is MVVM oriented.我想建议一个面向 MVVM 的解决方案。 One way to judge if we have an MVVM solution is if we can plan a unit test.判断我们是否有 MVVM 解决方案的一种方法是我们是否可以计划单元测试。 In this regard we would like to build a view model that is not attempting to raise a dialog and is just setting properties.在这方面,我们想构建一个视图 model,它不会尝试引发对话框,而只是设置属性。 I use a Popup that we bind to the view model.我使用我们绑定到视图 model 的弹出窗口。

The view model will look as following:视图 model 将如下所示:

public class MainViewModel:Binding 
    {
        bool _isQuestionRaised;
        public bool  IsQuestionRaised
        {
            get { return _isQuestionRaised; }
            set { _isQuestionRaised = value; NotifyPropertyChanged(nameof(IsQuestionRaised)); }
        }
        bool _yes;
        public bool Yes
        {
            get { return _yes; }
            set {
                _yes = value; 
                NotifyPropertyChanged(nameof(Yes));
                if (_yes) DoYesThings();
            }
        }
        bool _no;
        public bool No
        {
            get { return _no; }
            set {
                _no = value;
                NotifyPropertyChanged(nameof(No));
                if (_no) DoNoThings();
            }
        }
        public void DoYesThings()
        {
            IsQuestionRaised = false;
        }
        public void DoNoThings()
        {
            IsQuestionRaised = false;
        }
        public void QuestionIsRaised()
        {
            IsQuestionRaised = true;
        }
        public void QuestionIsDismissed()
        {
            IsQuestionRaised = false;
        }
    }

The XAML code: XAML代码:

<Grid>
        <Grid.Resources>
            <Style x:Key="btnStyle" TargetType="Button">
                <Setter Property="Height" Value="20"/>
                <Setter Property="Width" Value="40"/>
                <Setter Property="Margin" Value="10,10,10,10"/>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Button Grid.Row="0"  Click="Button_Click">Raise A Question</Button>
        <Popup IsOpen="{Binding IsQuestionRaised}" Width="300" Height="100"  Placement="Center"    >
            <Border BorderThickness="3">
            <StackPanel Background="Aqua"  Orientation="Vertical">
                <TextBlock Margin="20,0,0,20">Yes or No ?</TextBlock>
                <StackPanel Orientation="Horizontal">
                    <Button Click="Button_Click_Yes" Style="{StaticResource btnStyle}">Yes</Button>
                    <Button Click="Button_Click_No" Style="{StaticResource btnStyle}">No</Button>
                    <Button Click="Button_Click_Close" Style="{StaticResource btnStyle}">Close</Button>
                </StackPanel>
            </StackPanel>
            </Border>
        </Popup>
            
    </Grid>

I use here code behind but we can definitely use delegate command in the ViewModel instead.我在这里使用代码隐藏,但我们绝对可以在 ViewModel 中使用委托命令。

public partial class MainWindow : Window
    {
        MainViewModel _mainViewModel = new MainViewModel();
        public MainWindow()
        {
            InitializeComponent();
            DataContext = _mainViewModel;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _mainViewModel.QuestionIsRaised();
        }

        private void Button_Click_Yes(object sender, RoutedEventArgs e)
        {
            _mainViewModel.Yes = true;
        }

        private void Button_Click_No(object sender, RoutedEventArgs e)
        {
            _mainViewModel.No = true;
        }

        private void Button_Click_Close(object sender, RoutedEventArgs e)
        {
            _mainViewModel.QuestionIsDismissed();
           
        }
    }  

I would recommend you to make a Window with its own Viewmodel and View.我建议您使用自己的 Viewmodel 和 View 制作一个 Window。 Like this: Add a new Window.像这样:添加一个新的 Window。 在此处输入图像描述

DialogWindow.xaml DialogWindow.xaml

<Window x:Class="ComboBoxItemPanel_Testing.Dialog_Window"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:ComboBoxItemPanel_Testing"
    mc:Ignorable="d"
    Title="Dialog_Window" Height="150" Width="400">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <StackPanel  HorizontalAlignment="Center"
                 VerticalAlignment="Center">
        <TextBlock Text="Give me a number!"/>
        <TextBox Text="{Binding Path=MyNumber}"/>

    </StackPanel>

    <StackPanel Orientation="Horizontal"
                Grid.Row="1"
                HorizontalAlignment="Center">

        <Button Content="Yes"
                Click="Yes_Button"
                Margin="10"/>
        <Button Content="No"
                Margin="10"
                Click="No_Button"/>
    </StackPanel>
</Grid>

DialogWinodw.xaml.cs DialogWinodw.xaml.cs

using System.Windows;

namespace ComboBoxItemPanel_Testing
{
    /// <summary>
    /// Interaction logic for Dialog_Window.xaml
    /// </summary>
    public partial class Dialog_Window : Window
    {
        public Dialog_Window(object datacontext)
        {
            InitializeComponent();
            DataContext = datacontext;
    }

    private void Yes_Button(object sender, RoutedEventArgs e)
    {
        DialogResult = true;
    }

    private void No_Button(object sender, RoutedEventArgs e)
    {
        DialogResult = false;
    }
}
}

Add a new class to define your ViewModel.添加一个新的 class 来定义您的 ViewModel。 DialogWindowViewModel.cs DialogWindowViewModel.cs

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace ComboBoxItemPanel_Testing
{
public class DialogWindowViewModel : INotifyPropertyChanged
{

    private int _myNumber;

    public int MyNumber
    {
        get => _myNumber;
        set 
        {
            if (_myNumber != value) 
            {
                _myNumber = value;
            }
        }
    }


    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        try
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        catch (Exception ex)
        {
            Console.WriteLine($"PropertyChanged event handler FAILED : {ex.Message}");
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}
}

And u can use this like this:你可以这样使用它:

            DialogWindowViewModel vm = new DialogWindowViewModel();
        Dialog_Window dialog = new Dialog_Window(vm);
        if (dialog.ShowDialog().Value)
        {
            //Clicked Yes button
            //use ur viewModel
            Console.WriteLine("Selected number: " + vm.MyNumber);
        }
        else 
        {
            //Clicked No Button
            Console.WriteLine("You didnt selected a number!");
        }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM