Как работает метод CanExecute ICommand? - PullRequest
1 голос
/ 11 октября 2019

Я рассмотрел несколько примеров реализации ICommand, и для меня следующий способ является самым простым:

class Command : ICommand {
    public Func<object, bool> CanDo { get; set; }
    public Action<object> Do { get; set; }

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

    public Command(Func<object, bool> CanDo, Action<object> Do) {
        this.CanDo = CanDo;
        this.Do = Do;
    }

    public bool CanExecute(object parameter) => CanDo(parameter);
    public void Execute(object parameter) => Do(parameter);
}

, и именно так я реализовал свое тестовое приложение. В дополнение к классу Command у меня есть следующий класс:

class Person : INotifyPropertyChanged {

    string firstName, lastName, enabled;

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

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

    public string Enabled {
        get => enabled;
        set { enabled = value;  Changed(); }
    }

    public Command MyCommand { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;

    public Person() {
        MyCommand = new Command(CanDo, Do);
    }

    void Changed(string name = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

    bool CanDo(object para) {
        if (FirstName == "test" && LastName == "test") {
            Enabled = "true";
            //Changed("Enabled");
            return true;
        }
        else {
            Enabled = "false";
            //Changed("Enabled");
            return false;
        }
    }

    void Do(object para) {
        FirstName = "first";
        LastName = "last";
    }
}

и в xaml у меня есть эти:

<Window ...>
    <Window.Resources>
        <local:Person x:Key="person"/>
    </Window.Resources>      
    <Grid DataContext="{StaticResource person}">
        <StackPanel>
            <TextBox Text="{Binding FirstName}"/>
            <TextBox Text="{Binding LastName}"/>
            <TextBlock Text="{Binding FirstName}"/>
            <TextBlock Text="{Binding LastName}"/>

            <Button Content="Click" Command="{Binding Path=MyCommand}"/>
            <Label Content="{Binding Enabled}"/>
        </StackPanel>         
    </Grid>
</Window>

После запуска приложения все, что япопробуйте набрать те TextBox, которые будут удалены немедленно, если я позвоню Changed() в setter из Enabled. Если я закомментирую Changed() в setter и раскомментирую два Changed("Enabled") в bool CanDo(object para), он будет работать как положено!

Не должен ли вызов Changed() один раз в setter быть эквивалентным этим двум Changed("Enabled") вызовам в bool CanDo(object para)?

1 Ответ

1 голос
/ 11 октября 2019

Вы пропускаете CallerMemberNameAttribute в Changed:

void Changed([System.Runtime.CompilerServices.CallerMemberName]string name = "") => 
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));

. Получается имя вызывающего свойства, поэтому вам не нужно вызывать Changed("Enabled"), а просто Changed() в установщике.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...