C# WPF的现代UI-ModernDialog:仅在某些条件下允许单击“确定”

C# WPF的现代UI-ModernDialog:仅在某些条件下允许单击“确定”,c#,wpf,validation,modern-ui,C#,Wpf,Validation,Modern Ui,我启动了一个新的小项目,将ModernUI用于WPF 我必须显示一个只有两个文本框和两个按钮的对话框(确定/取消) 这两个文本框有一些验证(一个是名称,应该大于0,另一个应该是电子邮件) 目前我有以下几点: var userEditionForm = new UserEditionForm(oneUserConfigurationViewModel); var dlg = new ModernDialog { Title =

我启动了一个新的小项目,将ModernUI用于WPF

我必须显示一个只有两个文本框和两个按钮的对话框(确定/取消)

这两个文本框有一些验证(一个是名称,应该大于0,另一个应该是电子邮件)

目前我有以下几点:

        var userEditionForm = new UserEditionForm(oneUserConfigurationViewModel);
        var dlg = new ModernDialog
        {
            Title = "User edition",
            Content = userEditionForm,
            Width = 300
        };
        dlg.Buttons = new[] {dlg.OkButton, dlg.CancelButton};
        dlg.ShowDialog();
        return dlg.DialogResult.HasValue && dlg.DialogResult.Value;
内容用户控件是:

<UserControl x:Class="Test.UserControls.UserEditionForm"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             mc:Ignorable="d"
             d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
        <StackPanel Orientation="Vertical">
            <StackPanel.Resources>
                <Style TargetType="StackPanel">
                    <Setter Property="Orientation" Value="Horizontal" />
                    <Setter Property="Margin" Value="0,0,0,4" />
                </Style>
                <Style TargetType="Label" BasedOn="{StaticResource {x:Type Label}}">
                    <Setter Property="Width" Value="100" />
                    <Setter Property="VerticalAlignment" Value="Center" />
                </Style>
            </StackPanel.Resources>

            <StackPanel>
                <Label Content="Name" Target="{Binding ElementName=TextFirstName}" />
                <TextBox x:Name="TextFirstName" Width="150"
                         Text="{Binding User.Name, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, ValidatesOnDataErrors=True}" />
            </StackPanel>
            <StackPanel>
                <Label Content="Email" Target="{Binding ElementName=TextEmail}" />
                <TextBox x:Name="TextEmail" Width="150"
                         Text="{Binding User.Email, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay, ValidatesOnDataErrors=True}" />
            </StackPanel>
        </StackPanel>
    </Grid>
</UserControl>


已经进行了验证,但我想阻止用户单击“确定”,直到验证完成。可能吗?如果是,怎么做?

这实际上很棘手,但对我来说很有效:

视图模型

public class UserInfo : INotifyPropertyChanged, IDataErrorInfo
{
    private static Regex emailRegex = new Regex(@"^\w+(?:\.\w+)*?@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$");

    private string firstname;
    private string email;

    public string FirstName
    {
        get { return firstname; }
        set { firstname = value; OnPropertyChanged(); }
    }

    public string EMail
    {
        get { return email; }
        set { email = value; OnPropertyChanged(); }
    }

    public string Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get
        {
            switch (columnName)
            {
                case "FirstName":
                    return string.IsNullOrWhiteSpace(FirstName) ? "Firstname is required!" : null;
                case "EMail":
                    return EMail == null || !emailRegex.IsMatch(EMail) ? "The Email Address is not valid!" : null;
                default:
                    return null;
            }
        }
    }

    public LoginCommand LoginCommand { get; private set; }

    public UserInfo()
    {
        LoginCommand = new LoginCommand(this);
    }

    private void OnPropertyChanged([CallerMemberName]string propertyName = "")
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
命令(不知道您想叫它什么…)

与ModernUI一起使用

UserInfo info = new UserInfo();
UserInfoForm form = new UserInfoForm(info);
ModernDialog dialog = new ModernDialog
{
    Title = "User edition",
    Content = form,
    Width = 300
};
Button btnOk = dialog.OkButton;
ICommand originalCommand = btnOk.Command; //the original command should close the window so i keep it
btnOk.Command = info.LoginCommand;
info.LoginCommand.AttachCommand(originalCommand); //and attach it to my command
dialog.Buttons = new[] { btnOk, dialog.CancelButton };
dialog.ShowDialog();

不确定现代UI,但通常使用ICommand接口定义命令。。。此命令有一个CanExecute方法,该方法返回bool。。。Execute方法可以设置dialogresult。。。当用户输入数据(INotifyPropertyChanged)引用时,CanExecuteChanged可能会触发:作为旁注:您不必使命令成为viewmodel的成员,但这是常见的做法,自定义命令就像是原始命令的装饰器,我很确定您可以重构它,使其更具可读性,但它可以达到目的。更简单的方法是将您自己的按钮放在用户控件上,并将按钮绑定到命令,因为这是常见的mvvm实践。这非常好,我喜欢。我只是想理解
CanExecute
背后的逻辑:为什么只需要检查这些值是否为空?因为如果它们不为null,就意味着它们通过了验证?非常感谢您的时间:)我喜欢这种很好的方法(冗长,但很好)
UserInfo info = new UserInfo();
UserInfoForm form = new UserInfoForm(info);
ModernDialog dialog = new ModernDialog
{
    Title = "User edition",
    Content = form,
    Width = 300
};
Button btnOk = dialog.OkButton;
ICommand originalCommand = btnOk.Command; //the original command should close the window so i keep it
btnOk.Command = info.LoginCommand;
info.LoginCommand.AttachCommand(originalCommand); //and attach it to my command
dialog.Buttons = new[] { btnOk, dialog.CancelButton };
dialog.ShowDialog();