【问题标题】:How do I pass a variable as a CommandParameter如何将变量作为 CommandParameter 传递
【发布时间】:2012-09-04 11:23:18
【问题描述】:

我正在尝试将 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);
           }
        }
     }
  }
}

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;
     }
  }
}

xaml 如下所示:

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

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

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

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

并将 xaml 更改为:

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

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

【问题讨论】:

  • 我总是绑定属性public,我想他们一定是但不确定。
  • 不是问题的原因,但是从CanExecute 提升CanExecuteChanged 是错误的。当调用者再次调用CanExecute 时,应该引发CanExecuteChanged。根据您当前的CanExecute 实现,当一个人的年龄发生变化时,您应该提出CanExecuteChanged,但您也可能根本不提出该事件而侥幸。
  • 你试过tracing吗?你看到了什么错误?

标签: c# wpf mvvm command commandparameter


【解决方案1】:

CommandParameter 是否始终为空,或者您只在第一次执行时检查它?

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

尝试将 CommandParameter 属性移到 Command 属性之前:

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

另外,请参阅 herehere

编辑

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

命令:

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);
      }
  }
}

还有视图模型:

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();
      }
    }
}

【讨论】:

  • 哎呀。看看Button 做了什么,你的答案是一个明确的改进,但仍然不完整。 Command.CanExecuteCommandParameter 改变时永远不会被调用,所以如果PersonModelProp 可以在EditPersonCommand 不改变时改变,你将不会得到你希望的行为。
  • @hvd 你是对的。就像您在原始评论中提到的那样,每当 PersonModelProp 属性更改时,都应该进行更改以引发 CanExecuteChanged 事件。
【解决方案2】:

两点回答:

首先,正如@akton 提到的,您只能绑定到公共属性。不过,它不必DependencyProperty

其次,我花了一些时间弄清楚,你必须为 CommandParameter before Command 属性设置绑定.即

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

希望这会有所帮助:)

【讨论】:

  • 在 Visual Studio 2015 社区中,任何将 CommandParamater 移动到 Command 上方的尝试都将在保存文档时被撤销。换句话说,保存文档会强制将CommandParameter 置于Command 之下。这是 VS2015 的默认行为,因为它基本上是未经修改的安装。
【解决方案3】:

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

【讨论】:

  • 是的,我尝试将其设为公共财产,但也没有用。
  • @SwDevMan81 它是依赖属性吗?您是否触发了 PropertyChanged 事件?
  • 查看我的更新。它不是依赖属性,但 ViewModel 确实实现了 INotifyPropertyChanged 并调用了 PropertyChanged 事件。还有其他想法吗?
  • @SeDevMan81 是时候进行一些二进制调试了。更改 PersonModelProp 以返回硬编码的 int 并查看它是否有效。如果是这样,那就是绑定有问题。如果它不起作用,则可能是 XAML 中的拼写错误之类的。
  • 如果我将 Prop 更改为 int,它仍然会将参数设置为 null,但是如果我按照其他人的建议将 CommandParameter 放在 Command 绑定之前,它可以工作。那很奇怪。感谢您的帮助,是时候弄清楚为什么订单很重要了......
【解决方案4】:

我认为你的 EditPersonCommand 有问题(它没有正常触发)。我用 relayCommand 检查它并且它工作!

这是代码:

视图模型:

 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");
            }
        }


    }

还有这个 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:

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

【讨论】:

    猜你喜欢
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    • 2014-06-03
    • 2019-03-23
    • 1970-01-01
    相关资源
    最近更新 更多