c# - 在文本框中发生任何更改时立即更改按钮的启用状态?

标签 c# wpf xaml mvvm data-binding

我使用数据绑定(bind)和命令绑定(bind)来设置按钮的启用状态,具体取决于特定字符串属性是否具有值。或者您可能会说,我有一个强制文本框,并且我希望用户在输入至少 1 个字符之前不能单击确定。

我的代码正是这样做的,只是按钮的启用状态在 TextBox 未聚焦之前不会更新,例如按 T​​ab 键。我希望在 TextBox 内容发生任何变化时立即发生这种情况。我怎样才能做到这一点?当然,无需突破 MVVM!

查看:

<Window x:Class="Gebietsmanager.GebietBearbeitenDlg.View"
        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:Gebietsmanager.GebietBearbeitenDlg"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance local:ViewModel}"
        Title="Gebiet bearbeiten" Height="110" Width="300" WindowStartupLocation="CenterOwner" ShowInTaskbar="False" ResizeMode="NoResize">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Label Margin="8,8,0,0">Name:</Label>
        <TextBox Grid.Column="1" Text="{Binding Name}" Margin="8,8,8,0"/>
        <StackPanel Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" Margin="8,8,0,0">
            <Button IsDefault="True" Command="{Binding Commit}">Ok</Button>
            <Button Command="{Binding Rollback}" Margin="8,0,0,0">Reset</Button>
            <Button IsCancel="True" Margin="8,0,0,0">Cancel</Button>
        </StackPanel>
    </Grid>
</Window>

查看型号:
using System.ComponentModel;

namespace Gebietsmanager.GebietBearbeitenDlg
{
    public class ViewModel : INotifyPropertyChanged
    {
        public ViewModel(Gebiet gebiet)
        {
            _gebiet = gebiet;
            _gebietCopy = new Gebiet();
            Helpers.CopyPropValues(_gebietCopy, gebiet);

            Commit = new Command(
                () => Helpers.CopyPropValues(_gebiet, _gebietCopy),
                () => !string.IsNullOrEmpty(_gebietCopy.Name));
            Rollback = new Command(DoRollback);
        }

        private readonly Gebiet _gebiet;
        private readonly Gebiet _gebietCopy;

        private void DoRollback()
        {
            Helpers.CopyPropValues(_gebietCopy, _gebiet);
            OnPropertyChanged();
        }

        public string Name
        {
            get { return _gebietCopy.Name; }
            set
            {
                if (_gebietCopy.Name != value)
                {
                    _gebietCopy.Name = value;
                    OnPropertyChanged(nameof(Name));
                }
            }
        }

        public Command Commit { get; private set; }
        public Command Rollback { get; private set; }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

命令实现:
using System;
using System.Windows.Input;

namespace Gebietsmanager
{
    public sealed class Command : ICommand
    {
        public Command(Action executeAction, Func<bool> canExecutePredicate = null)
        {
            _executeAction = executeAction;
            _canExecutePredicate = canExecutePredicate;
        }

        private readonly Action _executeAction;
        private readonly Func<bool> _canExecutePredicate;

        public void Execute(object parameter)
        {
            _executeAction?.Invoke();
        }

        public bool CanExecute(object parameter)
        {
            return _canExecutePredicate?.Invoke() ?? true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

最佳答案

您需要设置UpdateSourceTrigger=PropertyChanged在你的绑定(bind)中,

MVVMLight 示例:

XAML

<Window x:Class="WpfApplication2.MainWindow"
        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:local="clr-namespace:WpfApplication2"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="525"
        Height="350"
        mc:Ignorable="d">
    <Window.DataContext>
        <local:MyModel />
    </Window.DataContext>
    <Grid>
        <StackPanel>
            <TextBlock Text="Name" />
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
            <Button Content="Go !" IsEnabled="{Binding IsReady}" />
        </StackPanel>
    </Grid>
</Window>

代码
internal class MyModel : ViewModelBase
{
    private string _name;

    public string Name
    {
        get { return _name; }
        set
        {
            Set(() => Name, ref _name, value);
            RaisePropertyChanged(() => IsReady);
        }
    }

    public bool IsReady
    {
        get { return !string.IsNullOrEmpty(Name); }
    }
}

关于c# - 在文本框中发生任何更改时立即更改按钮的启用状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36484778/

相关文章:

c# - 通过鼠标拖动滚动

c# - 在 Moq 中分配 out/ref 参数

c# - 通过触发器更改文本 block 中文本的颜色

c# - 获取 TextBox 的 FontFamily 作为字符串 XAML C#

c# - WPF 数据绑定(bind)组合框到列表<string>

xaml - 如何在 WP7 Bing Map 控件上放置多个圆形叠加层?

c# - UAC elevation 不允许拖放

c# - 什么是最快的 winforms 数据网格?

wpf - 有没有办法直接在 WPF 应用程序中运行 winforms exe?

wpf - 扩展器、网格和列表框 = 无虚拟化