C # WPF, встроенный в интерфейс ICommand и командный дизайн Patttern - PullRequest
1 голос
/ 11 марта 2019

Я новичок в WPF и C # в целом. Я читал о шаблоне Command Design и с нетерпением ждал возможности применить его в моем новом приложении, чтобы оно могло выполнять и отменять функциональность. Затем я понял, что WPF уже поставляется с интерфейсом ICommand и что кнопки de xml могут его реализовать. У указанного интерфейса есть такие методы:

public bool CanExecute(object parameter)
{
}

private void OnCanExecuteChanged()
{
}

public void Execute(object parameter)
{
}

Итак, я должен добавить функцию отмены к этой уже встроенной версии интерфейса ICommand, используя какой-либо другой интерфейс, наследуемый от него, и добавить метод отмены?

этот интерфейс только для кнопок? Я имею в виду, я хотел бы создать много других команд, которые не обязательно связаны с кнопкой xnml

спасибо заранее!

Ответы [ 4 ]

1 голос
/ 11 марта 2019

Прежде всего, команды являются частью шаблона MVVM, и вы должны сначала прочитать об этом.

Интерфейсы в C # не предоставляют никакой функциональности, они только описывают, как должен работать класс, который наследует этот интерфейс. Если вы хотите, чтобы класс что-то делал, вы не должны оставлять эти методы пустыми.

Команды в WPF представляют собой некую структуру, в которую логика будет передаваться позже. Наиболее логичное использование команд - привязать их к кнопкам.

Пример реализации ICommand:

public class RelayCommand : ICommand
{
    private readonly Action<object>     execute;
    private readonly Func<object, bool> canExecute;

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

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        this.execute    = execute;
        this.canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return canExecute == null || canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        execute(parameter);
    }
}

Команда на примере:

 public static RelayCommand NavigateToSignInPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new LoginForm()));

    public static RelayCommand NavigateToSignUpPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new RegistrationForm()));

    public static RelayCommand NavigateToStartPage => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateTo(new StartPage()));

    public static RelayCommand NavigateBack => new RelayCommand(
        actionParameter => Application.Instance.Navigation.NavigateBack(),
        actionPossibilityParameter => Application.Instance.Navigation.BackNavigationPossible);

Пример привязки команды: В представлении (xaml):

<Button x:Name="CancelButton"
            Content="Cancel"
            Command="{Binding CancelCommand}"
            Grid.Row="2"
            IsCancel="True"
            HorizontalAlignment="Left"
            Margin="44,0,0,0"
            Width="118" Height="23"
            VerticalAlignment="Center" />

В ViewModel:

        public RelayCommand CancelCommand => NavigationCommands.NavigateBack;
0 голосов
/ 12 марта 2019

Многие ответы подчеркивают полезную реализацию интерфейса ICommand с использованием делегатов.Вы можете даже пойти дальше, связавшись с изменениями модели, как показано ниже, или произвольно отфильтровать, если вы того пожелаете.Это может быть полезно для переоценки того, должна ли команда запускаться в зависимости от состояния модели, поскольку она напрямую связана с состоянием кнопки «Включено».

public class ObservableCommand<T> : ICommand where T : System.ComponentModel.INotifyPropertyChanged
{
    Predicate<object> _predicate;
    Action<object> _execute;
    public ObservableCommand(T model, Action<object> execute, Predicate<object> predicate)
    {
        model.PropertyChanged += ModelChanged;
        _execute = execute;
        _predicate = predicate;
    }

    public event EventHandler CanExecuteChanged;

    private void ModelChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    public bool CanExecute(object parameter)
    {
        return _predicate(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }
} 

По поводу вашего вопроса оотменить операции.Вы, конечно, можете использовать команду, чтобы вызвать это, но отслеживание состояния ваших объектов является более сложной частью.Вы можете использовать шаблон дизайна сувенира и связать свою команду с функцией восстановления состояния.Это упрощение, но оно было ядром реализаций, которые я делал в прошлом.

public class Memento<T>
{
    public Memento(T startState)
    {
        this.State = startState;
        this.OriginalState = startState;
    }

    public T State { get; set; }

    public T OriginalState { get; }

    public void RestorOriginalState()
    {
        State = OriginalState;
    }
}
0 голосов
/ 11 марта 2019

Я думаю, что вы путаете разные вещи прямо здесь.ICommand Interface - это то, что используется для привязки событий пользовательского интерфейса к коду, используемому в шаблонах проектирования, таких как MVVM .Command Design Pattern, который вы пытаетесь реализовать, - это архитектура состояний для отмены действий , как нажатие кнопки.

0 голосов
/ 11 марта 2019
  1. CanExecute приведет вас к тому, выполнять команду или нет, для команды Command вы можете увидеть здесь .
  2. Привязка Команды к кнопке - это привязка к элементу управления, а не к кнопке. Таким образом, все привязки «Команды», а не ограничения по нажатию, а также проверки, отбрасывания, фокусировки и т. Д. Работают
...