Wpf 如何绑定ComboBoxItem';s IsEnabled属性,以生成命令的结果';s CanExecute方法

Wpf 如何绑定ComboBoxItem';s IsEnabled属性,以生成命令的结果';s CanExecute方法,wpf,xaml,data-binding,isenabled,Wpf,Xaml,Data Binding,Isenabled,我有一个自定义的SplitButton实现,其中包含一个ComboBox,其中有几个绑定到命令的ComboBoxItems。我可以绑定到命令的名称和文本属性,但无法将ComboBoxItem的IsEnabled属性绑定到命令的CanExecute方法的结果,因为它是一个方法。是否有一些我不知道的绑定到方法的语法,或者是否有一些技巧可以帮助我绑定到CanExecute 顺便说一句,我曾考虑过使用自定义ValueConverter,但我意识到在重新评估CanExecute时可能不会收到任何更新,因为

我有一个自定义的SplitButton实现,其中包含一个ComboBox,其中有几个绑定到命令的ComboBoxItems。我可以绑定到命令的名称和文本属性,但无法将ComboBoxItem的IsEnabled属性绑定到命令的CanExecute方法的结果,因为它是一个方法。是否有一些我不知道的绑定到方法的语法,或者是否有一些技巧可以帮助我绑定到CanExecute

顺便说一句,我曾考虑过使用自定义ValueConverter,但我意识到在重新评估CanExecute时可能不会收到任何更新,因为它不是属性,而且我的命令不是业务对象。在我看来,此时我可能必须为命令创建一个ViewModel,以便仅在自定义SplitButton控件中使用,但这似乎有点过分。

您可以在ItemContainerStyle(ComboBoxItem样式)中放置一个按钮(如果在controltemplate中没有绑定到ICommand的按钮)并将命令绑定到它 并添加一个触发器来检查Button.IsEnabled并将该值设置为ComboBoxItem。所以这里我们使用Button作为命令源,只是为了从CanExecute获取IsEnabled。您可以将按钮的高度和宽度设置为零

 <ControlTemplate....>
   <Grid ...
       <Button x:Name="dummyButton" Command="{Binding YourCommand}" ....
           ......
   </Grid>

   <ControlTemplate.Triggers>
      <Trigger SourceName="dummyButton" Property="IsEnabled" Value="False">
        <Setter Property="IsEnabled" Value="False"/>
      </Trigger>
   </ControlTemplate.Triggers>


另一个解决方案是ViewModel。下面是我如何使用ViewModel来解决我的问题。请注意,nifty NotifyPropertyChanged方法是我的基本ViewModel类的一部分

public class RoutedUICommandViewModel : ViewModel
{
    private RoutedUICommand _command;
    private IInputElement _target;

    public string Name { get { return _command.Name; } }

    public string Text { get { return _command.Text; } }

    public bool CanExecute
    {
        get
        {
            return _command.CanExecute(null, _target);
        }
    }

    public RoutedUICommand Command { get { return _command; } }

    public RoutedUICommandViewModel(ReportCommand command, IInputElement target)
    {
        _command = command;
        _target = target;
        _command.CanExecuteChanged += _command_CanExecuteChanged;
    }

    private void _command_CanExecuteChanged(object sender, EventArgs e)
    {
        base.NotifyPropertyChanged(() => this.CanExecute);
    }
}
我在MSDN论坛上发现,在那里我建议使用一个来解决这个确切的问题。他给出了下面如何使用它的例子

<Grid behaviors:CommandBehaviors.EnablingCommand="{x:Static commands:testcommand.test}">  
  . . .  
</Grid> 

. . .  

虽然这个解决方案看起来很不错,但我还没能花时间确切地理解这种行为是如何实现的以及涉及到什么。如果有人想详细说明,请执行其他操作。如果我有机会探索此选项,我将用更多细节修改此答案。

我在代码中解决此问题的方法是在PreviewMouseDown事件的组合框上添加事件处理程序。下面是处理程序:

private void comboBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            ViewModel vm = this.DataContext as ViewModel;

            if (vm != null)
            {
                if (!vm.CanChangeSelection())
                {
                    e.Handled = true;
                    vm.RespondToFailedAttemptChangeUnits();
                }
            }
        }
这对我来说非常有用,因为我只需要在一个位置执行此操作。如果我有很多这样的页面,它可能会有点泰迪乌斯


虽然我遵循MVVM模式,但我不是一个纯粹主义者——我认为这是一个遵循MVVM精神的好的实际解决方案,如果不是字母。

整洁,我认为这肯定属于诡计范畴,但我喜欢它。若并没有人想出更优雅的东西,我会用这个。是的,当然这是棘手的,因为你们的要求也一样。正确的方法是添加bool ViewModel属性,如果要执行ICommand.canecute到dependancProperty绑定,这是我能看到的最好的方法。我同意,我认为我的评论可能是错误的。最后,我不能真正使用虚拟按钮的概念,因为我要声明我的ComboBoxItems,需要一个按钮。由于没有地方可以方便地放置我的虚拟按钮,我选择了不同的解决方案。哦,如果你有一个按钮,那么,不要再添加一个虚拟按钮。我假设你没有按钮在里面。我接受这个答案只是因为它是目前我决定在我的情况下使用的。不过,其他解决方案是可以接受的,我也将计划投票支持其他任何一种解决方案。