【问题标题】:Viewmodel Binding to CommandParameter that uses a Converter in WPFViewmodel 绑定到在 WPF 中使用转换器的 CommandParameter
【发布时间】:2020-01-31 19:59:47
【问题描述】:

我正在尝试将一个数字绑定到位于视图模型中的 Enum。我无法通过转换器将视图中的值传递给视图模型。这甚至可能吗?我还没有在网上看到任何解决这个问题的方法,我的尝试也没有奏效。

视图模型

public enum TimerOptions
{
    FifteenMinutes,
    OneHour, 
    Tomorrow
}

private ICommand _timerCommand;
public ICommand TimerCommand => _timerCommand ?? 
                           (_timerCommand = new RelayCommand<TimerOptions>(StartTimer));

private async void StartTimer(TimerOptions option){ .... }

查看

<Button Command="{Binding TimerCommand}" 
        Tag="0" 
        CommandParameter="{Binding Path=Tag, Converter={StaticResource BidirectionalEnumConverter}}">15 minutes</Button>

在上面的例子中,当用户点击按钮时,我希望我的函数获取FifteenMinutes的第一个枚举值作为参数。我已经尝试通过添加Tag(如图所示),将x:Name 添加到Button 并在绑定中使用SourcePath。没有任何效果。

这可能吗?我一直试图解决这个问题几个小时,我没有在网上找到任何东西。

【问题讨论】:

  • BidirectionalEnumConverter 是如何声明的?它的Convert() 方法是否曾经达到过?
  • 看来Command="{Binding StartTimer}"应该是Command="{Binding TimerComand}"。除此之外,为了将枚举值传递给 CommandParameter,只需编写 CommandParameter="{x:Static local:TimerOptions.FifteenMinutes}"
  • @PavelAnikhouski 我从这个答案stackoverflow.com/questions/7110464/… 中获取了转换器。它的工作原理与我在其他地方使用过的一样。
  • @Clemens 抱歉,这是一个错字。我拿走了我的代码并试图简化它并复制了错误的东西。我不能使用静态,因为枚举位于另一个项目中,在视图模型中。我不知道如何在 xaml 中导入它。
  • 通过引用库并添加 XAML 命名空间,如 xmlns:lib="clr-namespace:YourLibraryNamespace;assembly=YourLibraryAssembly"。然后写lib:TimerOptions.FifteenMinutes

标签: wpf data-binding


【解决方案1】:

我希望我的函数获取第一个枚举值 FifteenMinutes 作为参数。

为什么不直接根据命令参数中的字符串传递的信息在 VM 中执行转换器操作?

示例

<Button Command="{Binding TimerCommand}" 
        Tag="1" 
        CommandParameter=1

然后有一个基于它的 ICommand,例如

public ICommand TimerCommand =>
        new OperationCommand(async (oTag) => await StartTime(oTag).ConfigureAwait(true));

private bool IsOperation { get; set; }

private async void StartTimer(object oTag)
{
    int tagId = (int)oTag;
    //.... do the convert operations here...
      ...
   // Access VM properties here
   IsOperation = true;

    await  ....;

}


这是我使用的指挥结构,而不是 Relay。

public class OperationCommand : ICommand
{

    #region Variables

    private Func<object, bool> CanExecuteHandler { get; set; }
    private Action<object> ExecuteActionHandler { get; set; }

    public bool InSeparateThread { get; set; }
    #endregion

    #region Properties

    #endregion

    #region Construction/Initialization

    public OperationCommand(Action<object> executeAction, bool inSeparateThread = false)
    {
        InSeparateThread = inSeparateThread;
        ExecuteActionHandler = executeAction 
                                   ?? throw new ArgumentNullException(nameof(executeAction));
    }

    public OperationCommand(Action<object> executeAction, 
                            Func<object, bool> canExecute) : this(executeAction)
    {
        CanExecuteHandler = canExecute;
    }

    // Here to adhere to ICommand, change to below if needed
    //public event EventHandler CanExecuteChanged;
    event EventHandler ICommand.CanExecuteChanged
    {
        add {}
        remove {}
    }

    #endregion

    #region Methods

    public bool CanExecute(object parameter) => CanExecuteHandler?.Invoke(parameter) ?? true;

//        public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, new EventArgs());

    public void Execute(object parameter)
    {
        ExecuteActionHandler?.Invoke(parameter);
    }

    #endregion
}
}

【讨论】:

    猜你喜欢
    • 2011-08-17
    • 2010-12-17
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    • 2011-03-06
    • 2013-10-09
    • 1970-01-01
    • 2011-05-20
    相关资源
    最近更新 更多