Команды, предоставляющие доступ к WPF, C # и MVVM

#mvvm #c#-4.0 #binding

#mvvm #c #-4.0 #привязка

Вопрос:

Всем привет, я пытаюсь освоиться с использованием MVVM, но у меня возникают трудности : (во-первых, что касается моего вопроса, я использую код, приведенный в этой статье о MVVM, в качестве шаблона для моего обучения. Мой вопрос прост, как предоставлять независимые команды, в данном случае он создал список гиперссылок, но как мне создать единственную исправленную кнопку, которая выполняет то же самое, что и ссылка «создать нового клиента». Я создал нечто подобное этому (было добавлено в MainWindowViewModel.cs):

    public CommandViewModel exposedCommand
    {
        get
        {
             return new CommandViewModel(
              Strings.MainWindowViewModel_Command_CreateNewCustomer,
              new RelayCommand(param => this.CreateNewCustomer())
              );
        }
    }
  

а затем в документе xaml я создал новую кнопку, она была добавлена в MainWindow.xaml

          <Button 
            Content="Button" 
            Height="23" 
            HorizontalAlignment="Left" 
            Margin="6,303,0,0" Name="button1" VerticalAlignment="Top" Width="150"
            Command="{Binding Path=exposedCommand}"
        />
  

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

 Console.Writeline("HERE"); 
  

для метода exposedCommand
Он напечатал бы «ЗДЕСЬ», он просто ничего не сделает, когда вы нажмете кнопку.
Спасибо, любая помощь была бы очень признательна.

Ответ №1:

Ваш код XAML верен. Я также начал со статьи Джоша Смита о MVVM. Ниже приведен сокращенный пример того, как я реализую команды в своих ViewModels:

 public class ProjectViewModel : ViewModelBase
{
    // Private variable for holding save command
    private RelayCommand _saveCommand;

    // Other fields here

    // Constructors and properties and stuff here

    // Command Property for Save button. Bind XAML to "SaveCommand"
    public ICommand SaveCommand
    {
        get
        {
            if (_saveCommand == null) // Init command on first get
                _saveCommand = new RelayCommand(param => this.SaveChanges(), param => this.CanSave);

            return _saveCommand;
        }
    }

    /// <summary>
    /// Method called when save command is executed
    /// </summary>
    private void SaveChanges()
    {
        // Save logic here...
    }

    /// <summary>
    /// Predicate for determining if SaveCommand is enabled
    /// </summary>        
    private bool CanSave
    {
        get
        {
            return true; // Replace with SaveCommand predicate logic
        }
    }
}
  

Если это все еще не работает, проверьте выходные данные среды выполнения на наличие ошибок привязки. Если имеется ошибка привязки, которая подразумевает, что представление не может найти SaveCommand, то ваша ViewModel неправильно настроена в качестве DataContext представления. Дайте мне знать в комментариях, если это проблема.

Комментарии:

1. Привет, спасибо, чувак 🙂 Я добился того, что эта часть сработала, у меня возник еще один вопрос, касающийся строк или передачи команды другим ViewModels, как бы я это сделал? Не могли бы вы сказать мне, как я мог бы создать отдельную viewmodel, в которой есть команда, которую я хочу передать чему-то вроде функции addnewcusotmer, как бы я это сделал, эта ViewModel не наследует WorkSpaceViewModel, потому что она не закрывается. Как бы мне это сделать, чтобы при нажатии кнопки, являющейся частью новой ViewModel, она добавляла вкладку newcustomer в рабочую область?

2. Рад, что у вас все получилось. Не забудьте отметить как ответ. 🙂 Я предлагаю вам открыть новый вопрос по тому, что вы задали в комментарии выше — сложно ответить в комментарии, поскольку я не могу публиковать здесь блоки кода, и в качестве отдельной темы вопросов это также может помочь другим.

Ответ №2:

Вы можете привязать команду только к тем объектам, которые имеют реализацию интерфейса ICommand.

В вашем примере вы привязываетесь к объекту view model.

Вместо этого создайте свойство в модели представления, которое является типом RelayCommand, и свяжите это с button.

Это должно сработать.

Ответ №3:

Первое, что меня беспокоит, это ваш код внутри средства получения вашего свойства. Вы возвращаете новый объект КАЖДЫЙ раз при обращении к exposedCommand. На самом деле это не рекомендуется, вы должны сохранить это в резервном свойстве следующим образом:

 CommandViewModel _exposedCommand;
public CommandViewModel exposedCommand
{
  get
  {
     if (_exposedCommand == null)
     {
       _exposedCommand = new CommandViewModel(
       Strings.MainWindowViewModel_Command_CreateNewCustomer,
       new RelayCommand(param => this.CreateNewCustomer()));
     }
     return _exposedCommand;
  }
}
  

При этом типичный способ представления желаемого ICommand свойства примерно такой:

 RelayCommand _exposedCommand;
public ICommand exposedCommand
{
    get
    {
        if (_exposedCommand == null)
            _exposedCommand= new RelayCommand(param => this.CreateNewCustomer());
        return _exposedCommand;
    }
}