如果TextBox中的任何更改立即更改按钮的启用状态?

时间:2016-04-07 18:51:28

标签: c# wpf xaml mvvm data-binding

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

我的代码正是如此,只是在TextBox未聚焦之前没有更新按钮的启用状态,例如按Tab键。我希望在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; }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

您需要在绑定中设置UpdateSourceTrigger=PropertyChanged

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