Включить кнопку отключения на основе выбранных строк сетки данных WPF после MVVM С#

В моем приложении WPF у меня есть сетка данных

<DataGrid SelectedItem = "{Binding SelItm ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          ItemsSource = "{Binding Bills}"
          SelectionMode = "Extended"
          Name = "myGrid"...

Теперь я хочу включить кнопку, если выбраны какие-либо строки сетки данных, если строки не выбраны, кнопка должна быть отключена, довольно просто.

Моя кнопка xaml похожа на

<Button
    Command = "{Binding PreviewButtonClicked}"
    CommandParameter = "{Binding SelItm, ElementName=myGrid}"

Я создал стандартный класс RelayCommand

public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute)
            : this(execute, null)
        {
        }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            _execute = execute;
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute(parameter);
        }

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

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

И мой класс модели представления содержит:

public class myVM()
{
    private string _SelItm;
    public string SelItm
    {
        get { return _SelItm; }
        set
        {
            SetValue(ref _SelItm, value);
        }
    }
  public RelayCommand PreviewButtonClicked { get; set; }

  public myVM()
  {
    PreviewButtonClicked = new RelayCommand(ShowPDF, CanShowPDF);
  }
  
  public void ShowPDF(object param)
  {
    //do stuff
  }

  public bool CanShowPDF(object param)
  {
        if (SelItm.Any())
        {
            return true;
        }
            
        return false;
  }

}

Но когда я запускаю приложение, я получаю следующую ошибку в строке if (SelItm.Any())

System.ArgumentNullException: значение не может быть нулевым.

Что я делаю неправильно?

CommandParameter = "{Binding SelItm, ElementName=myGrid}" Что такое Selltm?... Этого свойства нет в сетке данных.
Felix Castor 19.11.2022 15:06

Это все равно не решает проблему. Вы указываете CommandParameter на элемент myGrid. Это означает, что путь указывает не на модель представления, а на сетку данных с несуществующим путем myGrid.SelItm. Измените SelItm -> SelectedItems.

Felix Castor 19.11.2022 15:37

Вы используете string.IsNullOrEmpty(this.SelItm), чтобы проверить, имеет ли строковая переменная значение. В вашем случае SelItm очевидно NULL. Это NULL, потому что DataGrid.SelectedItem имеет тип object и не может быть приведен к string (неправильный тип предмета). Тип — это элемент данных коллекции, связанный с DataGrid.SelectedItem.

BionicCode 19.11.2022 15:40

Кроме того, привязка Button.CommandParameter неверна. Прямо сейчас это не имеет никакого эффекта, поскольку вы не ссылаетесь на объект параметра в своем коде. Но если вы захотите сослаться на него из своих обработчиков команд, вы потерпите неудачу.

BionicCode 19.11.2022 15:43

@BionicCode, использующий if (!string.IsNullOrEmpty(this.Seltm)), выполнил свою работу, кстати, относительно привязки Button.CommandParameter. Я изначально не добавлял это в свой код, но, поскольку я получил ошибку, упомянутую в моем вопросе, я попытался добавить эту часть, это тоже не сработало. В любом случае спасибо.

Tamal Banerjee 19.11.2022 16:05
Асинхронная передача данных с помощью sendBeacon в JavaScript
Асинхронная передача данных с помощью sendBeacon в JavaScript
В современных веб-приложениях отправка данных из JavaScript на стороне клиента на сервер является распространенной задачей. Одним из популярных...
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Как подобрать выигрышные акции с помощью анализа и визуализации на Python
Отказ от ответственности: Эта статья предназначена только для демонстрации и не должна использоваться в качестве инвестиционного совета.
Принципы ООП в JavaScript
Принципы ООП в JavaScript
Парадигма объектно-ориентированного программирования имеет 4 основных принципа,
Пройдите собеседование по Angular: Общие вопросы и ответы экспертов
Пройдите собеседование по Angular: Общие вопросы и ответы экспертов
Можете ли вы объяснить разницу между ngOnInit и конструктором в Angular?
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Типы ввода HTML: Лучшие практики и советы
Типы ввода HTML: Лучшие практики и советы
HTML, или HyperText Markup Language , является стандартным языком разметки, используемым для создания веб-страниц. Типы ввода HTML - это различные...
0
5
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Есть как минимум три варианта.

Вариант 1 — программный код

Добавьте обработчик события SelectionChanged на DataGrid.

<DataGrid SelectedItem = "{Binding SelItm ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          ItemsSource = "{Binding Bills}"
          SelectionMode = "Extended"
          SelectionChanged = "DataGridSelectionChanged"
          Name = "myGrid"...

Событие SelectionChanged будет вызвано, когда будет выбрана полная строка. (Вы можете явно установить SelectionUnit как «Rows» в DataGrid) В противном случае используйте событие SelectedCellsChanged.

В обработчике события SelectionChanged:

private void DataGridSelectionChanged(object sender, SelectionChangedEventArgs args) 
{
    myButton.IsEnabled = myGrid.SelectedItems.Count > 0;
}

Вариант 2 Вы можете привязать свойство SelectedItem к DataGrid к вашей модели просмотра.

<DataGrid SelectedItem = "{Binding SelItm ,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          ItemsSource = "{Binding Bills}"
          SelectionMode = "Extended"
          SelectedItem = "{Binding SelectedItemInDataGrid}"
          Name = "myGrid"...

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

private object _selectedItemInDg;

public object SelectedItemInDataGrid 
{
    set { 
        _selectedItemInDg = value; 
        OnPropertyChanged(nameof(SelectedItemInDataGrid ));
        OnPropertyChanged(nameof(IsButtonEnabled)); 
        PreviewButtonClicked?.UpdateCanExecute();
    }
    get => _selectedItemInDg;
}

public bool IsButtonEnabled => _selectedItemInDg != null;

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

И ваша кнопка:

<Button IsEnabled = "{Binding IsButtonEnabled}" Command = "..." CommandParameter = "...">Content of button</Button>

Вариант 3 — в CanExecute

У вас есть метод в вашей модели представления, CanShowPDF(object param), который определяет для RelayCommand, может ли команда быть выполнена или нет. WPF автоматически включает/отключает кнопку на основе метода CanExecute экземпляра ICommand. Я бы добавил метод в класс RelayCommand:

public void UpdateCanExecute() {
    CanExecuteChanged?.Invoke();
}

Вызывайте метод UpdateCanExecute в вашем экземпляре RelayCommand каждый раз, когда что-то изменяется, что может повлиять на результат CanShowPDF.

Исключение

Вы спрашиваете об исключении, которое вы получаете:

System.ArgumentNullException: Value cannot be null.

Вероятно, вы вызываете метод для чего-то, что в данный момент равно null. Но трудно понять причину с данной информацией в вопросе, и я на самом деле не знаю, что такое SelItm, хотя, увидев имя, мы могли бы догадаться.

Можете ли вы показать, как сделать часть модели представления Варианта 2 для более старых версий С#, таких как С# 5.0? Также согласно вашему варианту 3 я не уверен, где и как мне вызвать метод UpdateCanExecute в моем экземпляре RelayCommand?

Tamal Banerjee 20.11.2022 02:37

Я обновил свой ответ. Кроме того, насколько я знаю, часть модели представления не зависит от версии С#. Он должен быть действителен для всех версий. Что вы не понимаете до сих пор?

user2190492 20.11.2022 16:11

Насколько мне известно, в части модели представления объявление свойств с использованием => не работает в более старой версии С#. Кроме того, у меня уже есть метод OnPropertyChanged в базовом классе модели представления (codeshare.io/r9VNXz). Кроме того, что будет CommandParameter в вашем варианте решения 2?

Tamal Banerjee 21.11.2022 05:19

Замените строку с => на get { return _selectedItemInDg; }. Части OnPropertyChanged в моем примере кода избыточны, просто напомню, что вы должны уведомлять об обновлении свойства. И параметр вашей команды может быть чем угодно.

user2190492 21.11.2022 17:59

Как преобразовать public bool IsButtonEnabled => _selectedItemInDg != null; в более старый код С#?

Tamal Banerjee 22.11.2022 10:05
public bool IsButtonEnabled { get { return _selectedItemInDg != null;}}
user2190492 22.11.2022 12:46

Другие вопросы по теме