Home > Mobile >  How to add a yes-no confirmation dialog in a WPF MVVM application?
How to add a yes-no confirmation dialog in a WPF MVVM application?

Time:01-20

I am developping a .net desktop WPF app in MVVM pattern using Visual Studio. 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. Could anyone help me to find a proper solution that solves my problem?

CodePudding user response:

I would like to suggest a solution that is MVVM oriented. One way to judge if we have an MVVM solution is if we can plan a unit test. In this regard we would like to build a view model that is not attempting to raise a dialog and is just setting properties. I use a Popup that we bind to the view model.

The view model will look as following:

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 :

<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.

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();
           
        }
    }  

CodePudding user response:

I would recommend you to make a Window with its own Viewmodel and View. Like this: Add a new Window. enter image description here

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

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. 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!");
        }
  • Related