ICommand参数始终为null

时间:2012-01-26 13:00:59

标签: c# wpf

我正在尝试将我的一些UI内容(文本框中的文本)作为参数提取到位于我的ViewModel中的ICommand方法中。

首先,我得到了这个RelayCommand实现:

/// <summary>
/// A command whose sole purpose is to relay its functionality to other
/// objects by invoking delegates. The default return value for the
/// CanExecute method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields

    #region Constructors

    /// <summary>
    /// Creates a new command that can always execute.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Creates a new command.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameters)
    {
        return _canExecute == null ? true : _canExecute(parameters);
    }

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

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

    #endregion // ICommand Members
}

我在我的ViewModel中声明了一个命令:

public ICommand AddEntityCommand
{
    get
    {
        if(_addEntity == null)
        {
            _addEntity = new RelayCommand(AddEntityToDb);
        }

        return _addEntity;
    }
}

这是我的xaml定义:

<Label Content="Entity Name:" Name="label1"/>
<TextBox Name="textBox_EntityName" />
<Label Content="Entity Type:" Name="label2" />
<TextBox Name="textBox_EntityType" />
<Button Content="Add" Name="btnAdd" Command="{Binding Path=AddEntityCommand}">
    <Button.CommandParameter>
        <MultiBinding Converter="{StaticResource MultiParamConverter}">
            <Binding Path="Text" ElementName="textBox_EntityName" />
            <Binding Path="Text" ElementName="textBox_EntityType" />
        </MultiBinding>
    </Button.CommandParameter>
</Button>

最后那是我的转换器:

public class MultiParamConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (object)values;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

我多次调试了这个工具,一旦我在文本框中更改了值,调试器就会在转换器内停止。在这种情况下,UI中的值显示在

object[] values

参数。 单击按钮,不会让我在转换中停止,但它会调用方法

AddEntityToDb

正确,但是参数,其类型为object [],总是包含两个都为null的元素。

我认为创建AddEntityCommand时我做了一些非常错误的事情,但我无法自己解决这个问题。 但是AddEntityToDb的参数总是包含两个null元素的原因是什么?

2 个答案:

答案 0 :(得分:3)

我不知道为什么它没有按预期工作,但无论如何你真的不需要使用命令参数......你可以将文本框绑定到ViewModel的属性,并使用这些属性的值在您的AddEntityToDb方法中。这是在MVVM中最常用的方法......


编辑: 我转发了转换器的初始问题。我认为原因是MultiBinding在调用values之后清除Convert数组(可能是为了避免内存泄漏)。修复是克隆数组而不是直接返回:

using System.Linq;

...


public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    return values.ToArray();
}

答案 1 :(得分:0)

更新:试试这个

public class MultiParamConverter : IMultiValueConverter
{
   public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
   {
      return new Tuple<string, string>((string)values[0], (string)values[1]);;
   }

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
    throw new NotImplementedException();
}
}

视图模型

public void AddEntityToDb(object parameter)
{
    var values = (Tuple<string, string>)parameter;
    var text1 = values.Item1;
    var text2 = values.Item2;
}