如何将变量作为CommandParameter传递

时间:2022-11-18 23:18:40

I'm trying to send a variable from the ViewModel as a parameter to a command. The command looks like this:

我正在尝试将ViewModel中的变量作为参数发送到命令。该命令如下所示:

public class EditPersonCommand : ICommand
{
  private bool _CanExecute = false;

  public bool CanExecute(object parameter)
  {
     PersonModel p = parameter as PersonModel;
     CanExecuteProperty = (p != null) && (p.Age > 0);
     return CanExecuteProperty;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter) { }

  private bool CanExecuteProperty
  {
     get { return _CanExecute; }
     set
     {
        if (_CanExecute != value)
        {
           _CanExecute = value;
           EventHandler can_execute = CanExecuteChanged;
           if (can_execute != null)
           {
              can_execute.Invoke(this, EventArgs.Empty);
           }
        }
     }
  }
}

The ViewModel looks like this:

ViewModel看起来像这样:

public class PersonViewModel : ViewModelBase
{
  private PersonModel _PersonModel;
  private EditPersonCommand _EditPersonCommand;

  ///<remarks>
  /// must use the parameterless constructor to satisfy <Window.Resources>
  ///</remarks>
  public PersonViewModel()
     : this(new PersonModel())
  {

  }

  public PersonViewModel(PersonModel personModel)
  {
     _PersonModel = personModel;
  }

  public ICommand EditPersonCommand
  {
     get
     {
        if (_EditPersonCommand == null)
        {
           _EditPersonCommand = new EditPersonCommand();
        }
        return _EditPersonCommand;
     }
  }
}

The xaml looks like this:

xaml看起来像这样:

<Button Content="Edit" HorizontalAlignment="Right" Height="20" Width="80"
   Command="{Binding EditPersonCommand}" 
   CommandParameter="{Binding _PersonModel}" />

I've tried creating a property in the ViewModel instead of using the private local variable name, but that didnt work either. The object parameter always shows null in the call to CanExecute and the button is never enabled. If I change the CommandParameter value to Hello, then I receive Hello in the call to CanExecute, so I'm not sure why the variable doesnt work. Any help would be appreciated.

我已经尝试在ViewModel中创建一个属性而不是使用私有本地变量名,但这也没有用。对象参数在对CanExecute的调用中始终显示为null,并且永远不会启用该按钮。如果我将CommandParameter值更改为Hello,那么我在调用CanExecute时收到Hello,所以我不确定为什么变量不起作用。任何帮助,将不胜感激。

Update: I've also tried making a public property to the model (which I dont really want to expose the model, but just tried it to see if it works, but it doesnt).

更新:我也试过为模型创建一个公共属性(我真的不想公开模型,但只是尝试了它是否有效,但它没有)。

// Added this to the ViewModel
public PersonModel PersonModelProp
{
  get
  {
     return _PersonModel;
  }
  set
  {
     _PersonModel = value;
     OnPropertyChanged("PersonModelProp");
  }
}

And changed the xaml to this:

并将xaml更改为:

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
   Command="{Binding EditPersonCommand}" 
   CommandParameter="{Binding PersonModelProp}" />

But still no luck. The ViewModel does implement INotifyPropertyChanged

但仍然没有运气。 ViewModel确实实现了INotifyPropertyChanged

4 个解决方案

#1


13  

Is the CommandParameter always null or are you only checking the first time it is being executed?

CommandParameter是否始终为null或者您是仅在第一次执行时进行检查?

It appears that the order in which you declare your properties matters in this case since setting the Command property causes the CanExecute to fire immediately before the CommandParameter has been set.

在这种情况下,您声明属性的顺序似乎很重要,因为设置Command属性会导致CanExecute在设置CommandParame之前立即触发。

Try moving the CommandParameter property before the Command property:

尝试在Command属性之前移动CommandParameter属性:

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
 CommandParameter="{Binding PersonModelProp}" 
 Command="{Binding EditPersonCommand}" />

Also, see here and here.

另外,请看这里和这里。

Edit

编辑

To ensure that your events are being raised properly you should raise the CanExecuteChanged event when the PersonModelProp value changes.

为确保正确引发事件,应在PersonModelProp值更改时引发CanExecuteChanged事件。

The Command:

命令:

public class EditPersonCommand : ICommand
{
  public bool CanExecute(object parameter)
  {
     PersonModel p = parameter as PersonModel;
     return p != null && p.Age > 0;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter) 
  {
      //command implementation
  }

  public void RaiseCanExecuteChanged()
  {
      var handler = CanExecuteChanged;
      if(handler != null)
      {
          handler(this, EventArgs.Empty);
      }
  }
}

And the view model:

和视图模型:

public class PersonViewModel : ViewModelBase
{
  private PersonModel _PersonModel;
  private EditPersonCommand _EditPersonCommand;

  ///<remarks>
  /// must use the parameterless constructor to satisfy <Window.Resources>
  ///</remarks>
  public PersonViewModel()
     : this(new PersonModel())
  {
      _EditPersonCommand = new EditPersonCommand();
  }

  public PersonViewModel(PersonModel personModel)
  {
     _PersonModel = personModel;
  }

  public ICommand EditPersonCommand
  {
     get
     {
         return _EditPersonCommand;
     }
  }

  public PersonModel PersonModelProp
  {
      get
      {
         return _PersonModel;
      }
      set
      {
         _PersonModel = value;
         OnPropertyChanged("PersonModelProp");
         EditPersonCommand.RaiseCanExecuteChanged();
      }
    }
}

#2


7  

Two points to the answer:

两点答案:

First, as @akton mentioned, you can only bind to public properties. It doesn't have to be a DependencyProperty though.

首先,正如@akton所提到的,您只能绑定到公共属性。但它不一定是DependencyProperty。

Second, which took me some tome to figure out, is that you have to set the binding for the CommandParameter before the Command property. i.e.

其次,我需要弄清楚的是,你必须在Command属性之前设置CommandParameter的绑定。即

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
        CommandParameter="{Binding PersonModelProp}"
        Command="{Binding EditPersonCommand}" />

Hope this helps :)

希望这可以帮助 :)

#3


4  

_PersonModel is private and so cannot be accessed. Create a public property that exposes it and bind to that in the CommandParameter. Remember to make the property a dependency property (technically not required but it helps) and the ViewModel should implement INotifyProperty changed and fire the PropertyChanged event so the binding is updated.

_PersonModel是私有的,因此无法访问。创建一个公开属性并将其绑定到CommandParameter中的公共属性。记住要使属性成为依赖属性(技术上不是必需的,但它有帮助),ViewModel应该实现更改的INotifyProperty并触发PropertyChanged事件,以便更新绑定。

#4


2  

I think you have a problem in your EditPersonCommand (it not fired ok).I check it with relayCommand and it work!

我认为你的EditPersonCommand有问题(它没有被解雇)。我用relayCommand检查它,它工作!

This is the code:

这是代码:

ViewModel:

视图模型:

 public class PersonViewModel : ViewModelBase
    {
        private PersonModel _PersonModel;
        private ICommand _EditPersonCommand;

        ///<remarks>
        /// must use the parameterless constructor to satisfy <Window.Resources>
        ///</remarks>
        public PersonViewModel()
            : this(new PersonModel())
        {

        }

        public PersonViewModel(PersonModel personModel)
        {
            PersonModelProp = personModel;
        }

        public ICommand EditPersonCommand
        {
            get
            {
                if (_EditPersonCommand == null)
                {
                    _EditPersonCommand = new RelayCommand(ExecuteEditPerson,CanExecuteEditPerson);
                }
                return _EditPersonCommand;
            }
        }


        private bool CanExecuteEditPerson(object parameter)
        {
            PersonModel p = parameter as PersonModel;

            return (p != null) && (p.Age > 0);
        }


        private void ExecuteEditPerson(object o)
        {

        }


        public PersonModel PersonModelProp
        {
            get
            {
                return _PersonModel;
            }
            set
            {
                _PersonModel = value;
                NotifyPropertyChanged("PersonModelProp");
            }
        }


    }

And this RelayCommand (Fire events ok!)

而这个RelayCommand(火灾事件还可以!)

      public class RelayCommand : ICommand
        {
            #region Constants and Fields


            private readonly Predicate<object> canExecute;


            private readonly Action<object> execute;

            #endregion

            #region Constructors and Destructors


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

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

                this.execute = execute;
                this.canExecute = canExecute;
            }

            #endregion

            #region Events


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

                remove
                {
                    CommandManager.RequerySuggested -= value;
                }
            }

            #endregion

            #region Implemented Interfaces

            #region ICommand


            [DebuggerStepThrough]
            public bool CanExecute(object parameter)
            {
                return this.canExecute == null || this.canExecute(parameter);
            }

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

            #endregion

            #endregion
        }

Xmal:

Xmal位:

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
 CommandParameter="{Binding PersonModelProp}" 
 Command="{Binding EditPersonCommand}" />

#1


13  

Is the CommandParameter always null or are you only checking the first time it is being executed?

CommandParameter是否始终为null或者您是仅在第一次执行时进行检查?

It appears that the order in which you declare your properties matters in this case since setting the Command property causes the CanExecute to fire immediately before the CommandParameter has been set.

在这种情况下,您声明属性的顺序似乎很重要,因为设置Command属性会导致CanExecute在设置CommandParame之前立即触发。

Try moving the CommandParameter property before the Command property:

尝试在Command属性之前移动CommandParameter属性:

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
 CommandParameter="{Binding PersonModelProp}" 
 Command="{Binding EditPersonCommand}" />

Also, see here and here.

另外,请看这里和这里。

Edit

编辑

To ensure that your events are being raised properly you should raise the CanExecuteChanged event when the PersonModelProp value changes.

为确保正确引发事件,应在PersonModelProp值更改时引发CanExecuteChanged事件。

The Command:

命令:

public class EditPersonCommand : ICommand
{
  public bool CanExecute(object parameter)
  {
     PersonModel p = parameter as PersonModel;
     return p != null && p.Age > 0;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter) 
  {
      //command implementation
  }

  public void RaiseCanExecuteChanged()
  {
      var handler = CanExecuteChanged;
      if(handler != null)
      {
          handler(this, EventArgs.Empty);
      }
  }
}

And the view model:

和视图模型:

public class PersonViewModel : ViewModelBase
{
  private PersonModel _PersonModel;
  private EditPersonCommand _EditPersonCommand;

  ///<remarks>
  /// must use the parameterless constructor to satisfy <Window.Resources>
  ///</remarks>
  public PersonViewModel()
     : this(new PersonModel())
  {
      _EditPersonCommand = new EditPersonCommand();
  }

  public PersonViewModel(PersonModel personModel)
  {
     _PersonModel = personModel;
  }

  public ICommand EditPersonCommand
  {
     get
     {
         return _EditPersonCommand;
     }
  }

  public PersonModel PersonModelProp
  {
      get
      {
         return _PersonModel;
      }
      set
      {
         _PersonModel = value;
         OnPropertyChanged("PersonModelProp");
         EditPersonCommand.RaiseCanExecuteChanged();
      }
    }
}

#2


7  

Two points to the answer:

两点答案:

First, as @akton mentioned, you can only bind to public properties. It doesn't have to be a DependencyProperty though.

首先,正如@akton所提到的,您只能绑定到公共属性。但它不一定是DependencyProperty。

Second, which took me some tome to figure out, is that you have to set the binding for the CommandParameter before the Command property. i.e.

其次,我需要弄清楚的是,你必须在Command属性之前设置CommandParameter的绑定。即

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
        CommandParameter="{Binding PersonModelProp}"
        Command="{Binding EditPersonCommand}" />

Hope this helps :)

希望这可以帮助 :)

#3


4  

_PersonModel is private and so cannot be accessed. Create a public property that exposes it and bind to that in the CommandParameter. Remember to make the property a dependency property (technically not required but it helps) and the ViewModel should implement INotifyProperty changed and fire the PropertyChanged event so the binding is updated.

_PersonModel是私有的,因此无法访问。创建一个公开属性并将其绑定到CommandParameter中的公共属性。记住要使属性成为依赖属性(技术上不是必需的,但它有帮助),ViewModel应该实现更改的INotifyProperty并触发PropertyChanged事件,以便更新绑定。

#4


2  

I think you have a problem in your EditPersonCommand (it not fired ok).I check it with relayCommand and it work!

我认为你的EditPersonCommand有问题(它没有被解雇)。我用relayCommand检查它,它工作!

This is the code:

这是代码:

ViewModel:

视图模型:

 public class PersonViewModel : ViewModelBase
    {
        private PersonModel _PersonModel;
        private ICommand _EditPersonCommand;

        ///<remarks>
        /// must use the parameterless constructor to satisfy <Window.Resources>
        ///</remarks>
        public PersonViewModel()
            : this(new PersonModel())
        {

        }

        public PersonViewModel(PersonModel personModel)
        {
            PersonModelProp = personModel;
        }

        public ICommand EditPersonCommand
        {
            get
            {
                if (_EditPersonCommand == null)
                {
                    _EditPersonCommand = new RelayCommand(ExecuteEditPerson,CanExecuteEditPerson);
                }
                return _EditPersonCommand;
            }
        }


        private bool CanExecuteEditPerson(object parameter)
        {
            PersonModel p = parameter as PersonModel;

            return (p != null) && (p.Age > 0);
        }


        private void ExecuteEditPerson(object o)
        {

        }


        public PersonModel PersonModelProp
        {
            get
            {
                return _PersonModel;
            }
            set
            {
                _PersonModel = value;
                NotifyPropertyChanged("PersonModelProp");
            }
        }


    }

And this RelayCommand (Fire events ok!)

而这个RelayCommand(火灾事件还可以!)

      public class RelayCommand : ICommand
        {
            #region Constants and Fields


            private readonly Predicate<object> canExecute;


            private readonly Action<object> execute;

            #endregion

            #region Constructors and Destructors


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

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

                this.execute = execute;
                this.canExecute = canExecute;
            }

            #endregion

            #region Events


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

                remove
                {
                    CommandManager.RequerySuggested -= value;
                }
            }

            #endregion

            #region Implemented Interfaces

            #region ICommand


            [DebuggerStepThrough]
            public bool CanExecute(object parameter)
            {
                return this.canExecute == null || this.canExecute(parameter);
            }

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

            #endregion

            #endregion
        }

Xmal:

Xmal位:

<Button Content="Edit" HorizontalAlignment="Right" Height="20"  Width="80"
 CommandParameter="{Binding PersonModelProp}" 
 Command="{Binding EditPersonCommand}" />