Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/307.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 用户输入确认_C#_Wpf_Mvvm - Fatal编程技术网

C# 用户输入确认

C# 用户输入确认,c#,wpf,mvvm,C#,Wpf,Mvvm,在尝试使用更通用的WPF方法(沿着MVVM的方式)之后,我遇到了一个问题 假设我有一个经典的Person类,它有三个字符串属性——FirstName、LastName、Fullname。前两个由用户通过两个文本框输入,全名为只读,以文本块打印 我有一个带有两个文本框的stackpanel。我将Person实例绑定到stackpanel的DataContext。它看起来像这样: <StackPanel x:Name="InputData" DataContext="{Binding Pers

在尝试使用更通用的WPF方法(沿着MVVM的方式)之后,我遇到了一个问题

假设我有一个经典的Person类,它有三个字符串属性——FirstName、LastName、Fullname。前两个由用户通过两个文本框输入,全名为只读,以文本块打印

我有一个带有两个文本框的stackpanel。我将Person实例绑定到stackpanel的DataContext。它看起来像这样:

<StackPanel x:Name="InputData" DataContext="{Binding Person}">
                    <Text="{Binding FirstName, Mode=TwoWay}"/>
                    <Text="{Binding LastName, Mode=TwoWay}"/>
                </StackPanel>
<TextBlock Text="{Binding FullName}"/>
现在我想避免对pp的意外更改。以前我使用事件和messagebox进行管理-在StackPanel失去焦点或用户按下Enter键后,出现了一个messagebox,询问是否更改pp

若用户选择“否”,那个么所有内容都将恢复到编辑前的原始状态

否则,pp和所有文本框将保存新值


现在,在尝试了绑定和MVVM之后,我真的不想回到所有这些事件,那么正确的方法是什么呢?

有多种方法可以实现这一点。
你以前处理事件的方法(可能?)还不错

我只需在程序/产品的MVVM库中创建一个类,其中包含要从UI库订阅的事件和方法

这里有一个例子来说明这一点

MVVM:

用户界面:

您只需在UI助手类中打开一个对话框。您可以将其更改为
EventArgs
[…],但您知道了

基本上你是在指导助手做某事。

UI级别负责执行正确的操作(例如,显示对话框或窗口)。

下面是一个非常基本和详细的示例,说明如何执行您正在寻找的操作。实现这一点的组件可以也应该被分解成进一步的处理组,但你会明白这一点

我将在这里包括3个类:ViewModel、PreviousState和RelayCommand。然后我将在视图中使用纯绑定。按原样运行此代码,它将通过纯MVVM以您希望的方式工作。然而;花点时间来解读正在发生的事情,因为有更深入更简单的方法来实现这个结果。我相信这是一个受过良好教育的例子,使用纯MVVM可以帮助您理解如何实现这一点。注意:这里使用了一些流行的技术,为了帮助您更好地理解这些技术,需要一个关于MVVM和XAML的短期课程。我的希望是,您可以将其分离开来,以便更好地理解它,并对其进行修改以满足您的需要

我把所有文件放在同一个名称空间中,他把ViewModel、RelayCommand和PreviousState类型都放在一个文件中,只是为了简化发布这个答案

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace Question_Answer_WPF_App
{
    public class PersonViewModel : INotifyPropertyChanged
    {
        string firstName = "Bob";
        string lastName = "Smith";
        string fullName;

        public PersonViewModel()
        {
            CommitStateCommand = new RelayCommand((obj) => CommitChanges(),(obj) => CanExecuteCommands());
            RevertStateCommand = new RelayCommand((obj) => RevertChanges(),(obj) => CanExecuteCommands());
            CommitChanges();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));

        public string FirstName
        {
            get => firstName;
            set
            {
                firstName = value;
                Notify();
                UpdateChanges();
            }
        }

        public string LastName
        {
            get => lastName;
            set
            {
                lastName = value;
                Notify();
                UpdateChanges();
            }
        }

        public string FullName
        {
            get => fullName;
            private set
            {
                fullName = value;
                Notify();
            }
        }

        private PersonState PreviousState { get; } = new PersonState();
        public RelayCommand CommitStateCommand { get; }
        public RelayCommand RevertStateCommand { get; }

        private void UpdateChanges()
        {
            FullName = $"{FirstName} {LastName}";
            CommitStateCommand.UpdateCanExecute();
            RevertStateCommand.UpdateCanExecute();
        }

        private void CommitChanges()
        {
            PreviousState.FirstName = FirstName;
            PreviousState.LastName = LastName;
            UpdateChanges();
        }

        private void RevertChanges()
        {
            FirstName = PreviousState?.FirstName;
            LastName = PreviousState?.LastName;
            CommitChanges();
        }

        private bool CanExecuteCommands() => PreviousState?.FirstName != FirstName || PreviousState?.LastName != LastName;
    }

    internal class PersonState
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class RelayCommand : ICommand
    {
        public Action<object> ExecuteFunction { get; }
        public Predicate<object> CanExecutePredicate { get; }
        public event EventHandler CanExecuteChanged;
        public void UpdateCanExecute() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

        public RelayCommand(Action<object> executeFunction) : this(executeFunction, (obj) => true) { }
        public RelayCommand(Action<object> executeFunction, Predicate<object> canExecutePredicate)
        {
            ExecuteFunction = executeFunction;
            CanExecutePredicate = canExecutePredicate;
        }

        public bool CanExecute(object parameter) => CanExecutePredicate?.Invoke(parameter) ?? true;
        public void Execute(object parameter) => ExecuteFunction.Invoke(parameter);
    }
}
使用系统;
使用系统组件模型;
使用System.Runtime.CompilerServices;
使用System.Windows.Input;
名称空间问题\答案\ WPF\应用程序
{
公共类PersonViewModel:INotifyPropertyChanged
{
string firstName=“Bob”;
字符串lastName=“Smith”;
字符串全名;
公共PersonViewModel()
{
CommitStateCommand=new RelayCommand((obj)=>CommitChanges(),(obj)=>CanExecuteCommands());
RevertStateCommand=new RelayCommand((obj)=>RevertChanges(),(obj)=>CanExecuteCommands());
提交更改();
}
公共事件属性更改事件处理程序属性更改;
私有void Notify([CallerMemberName]string property=”“)=>PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(property));
公共字符串名
{
get=>firstName;
设置
{
firstName=值;
通知();
UpdateChanges();
}
}
公共字符串姓氏
{
get=>lastName;
设置
{
lastName=值;
通知();
UpdateChanges();
}
}
公共字符串全名
{
get=>fullName;
专用设备
{
全名=值;
通知();
}
}
private PersonState PreviousState{get;}=new PersonState();
public RelayCommand CommitState命令{get;}
public RelayCommand RevertStateCommand{get;}
私有void UpdateChanges()
{
全名=$“{FirstName}{LastName}”;
CommitStateCommand.UpdateCanExecute();
RevertStateCommand.UpdateCanExecute();
}
私人无效佣金()
{
PreviousState.FirstName=FirstName;
PreviousState.LastName=LastName;
UpdateChanges();
}
私有void RevertChanges()
{
FirstName=以前的状态?.FirstName;
LastName=以前的状态?.LastName;
提交更改();
}
private bool CanExecuteCommands()=>PreviousState?.FirstName!=FirstName | | PreviousState?.LastName!=LastName;
}
内部类个人状态
{
公共字符串名{get;set;}
公共字符串LastName{get;set;}
}
公共类中继命令:ICommand
{
公共操作执行函数{get;}
公共谓词CanExecutePredicate{get;}
公共事件处理程序CanExecuteChanged;
public void UpdateCanExecute()=>CanExecuteChanged?.Invoke(此为EventArgs.Empty);
public RelayCommand(Action executeFunction):this(executeFunction,(obj)=>true){
公共RelayCommand(Action executeFunction,谓词canExecutePredicate)
{
ExecuteFunction=ExecuteFunction;
CanExecutePredicate=CanExecutePredicate;
}
public bool CanExecute(对象参数)=>CanExecutePredicate?.Invoke(参数)??true;
public void Execute(对象参数)=>ExecuteFunction.Invoke(参数);
}
}
main window.xaml

<Window x:Class="Question_Answer_WPF_App.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Question_Answer_WPF_App"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800">

    <Window.DataContext>
        <local:PersonViewModel />
    </Window.DataContext>

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="150" />
            <Setter Property="Margin" Value="4" />
        </Style>
    </Window.Resources>

    <StackPanel>
        <TextBlock Text="First Name"/>
        <TextBox Text="{Binding FirstName, Mode=TwoWay}"/>

        <TextBlock Text="Last Name"/>
        <TextBox Text="{Binding LastName, Mode=TwoWay}"/>

        <TextBlock Text="Full Name"/>
        <TextBlock Text="{Binding FullName}" />

        <StackPanel Orientation="Horizontal">
            <Button Content="Commit" 
                    Command="{Binding CommitStateCommand}" />
            <Button Content="Revert" 
                    Command="{Binding RevertStateCommand}" />
        </StackPanel>    
    </StackPanel>

</Window>
<
static class MessageResolver
{
    #region Constructor

    static MessageResolver()
    {
        MessageHelper.Exception += OnException;
    }

    #endregion

    #region Events

    static void OnException(Exception e)
    {
        new ExceptionDialog(e).ShowDialog();
    }

    #endregion
}
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;

namespace Question_Answer_WPF_App
{
    public class PersonViewModel : INotifyPropertyChanged
    {
        string firstName = "Bob";
        string lastName = "Smith";
        string fullName;

        public PersonViewModel()
        {
            CommitStateCommand = new RelayCommand((obj) => CommitChanges(),(obj) => CanExecuteCommands());
            RevertStateCommand = new RelayCommand((obj) => RevertChanges(),(obj) => CanExecuteCommands());
            CommitChanges();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void Notify([CallerMemberName] string property = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));

        public string FirstName
        {
            get => firstName;
            set
            {
                firstName = value;
                Notify();
                UpdateChanges();
            }
        }

        public string LastName
        {
            get => lastName;
            set
            {
                lastName = value;
                Notify();
                UpdateChanges();
            }
        }

        public string FullName
        {
            get => fullName;
            private set
            {
                fullName = value;
                Notify();
            }
        }

        private PersonState PreviousState { get; } = new PersonState();
        public RelayCommand CommitStateCommand { get; }
        public RelayCommand RevertStateCommand { get; }

        private void UpdateChanges()
        {
            FullName = $"{FirstName} {LastName}";
            CommitStateCommand.UpdateCanExecute();
            RevertStateCommand.UpdateCanExecute();
        }

        private void CommitChanges()
        {
            PreviousState.FirstName = FirstName;
            PreviousState.LastName = LastName;
            UpdateChanges();
        }

        private void RevertChanges()
        {
            FirstName = PreviousState?.FirstName;
            LastName = PreviousState?.LastName;
            CommitChanges();
        }

        private bool CanExecuteCommands() => PreviousState?.FirstName != FirstName || PreviousState?.LastName != LastName;
    }

    internal class PersonState
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class RelayCommand : ICommand
    {
        public Action<object> ExecuteFunction { get; }
        public Predicate<object> CanExecutePredicate { get; }
        public event EventHandler CanExecuteChanged;
        public void UpdateCanExecute() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);

        public RelayCommand(Action<object> executeFunction) : this(executeFunction, (obj) => true) { }
        public RelayCommand(Action<object> executeFunction, Predicate<object> canExecutePredicate)
        {
            ExecuteFunction = executeFunction;
            CanExecutePredicate = canExecutePredicate;
        }

        public bool CanExecute(object parameter) => CanExecutePredicate?.Invoke(parameter) ?? true;
        public void Execute(object parameter) => ExecuteFunction.Invoke(parameter);
    }
}
<Window x:Class="Question_Answer_WPF_App.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Question_Answer_WPF_App"
        mc:Ignorable="d"
        Title="MainWindow"
        Height="450"
        Width="800">

    <Window.DataContext>
        <local:PersonViewModel />
    </Window.DataContext>

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="150" />
            <Setter Property="Margin" Value="4" />
        </Style>
    </Window.Resources>

    <StackPanel>
        <TextBlock Text="First Name"/>
        <TextBox Text="{Binding FirstName, Mode=TwoWay}"/>

        <TextBlock Text="Last Name"/>
        <TextBox Text="{Binding LastName, Mode=TwoWay}"/>

        <TextBlock Text="Full Name"/>
        <TextBlock Text="{Binding FullName}" />

        <StackPanel Orientation="Horizontal">
            <Button Content="Commit" 
                    Command="{Binding CommitStateCommand}" />
            <Button Content="Revert" 
                    Command="{Binding RevertStateCommand}" />
        </StackPanel>    
    </StackPanel>

</Window>