How to bind a ComboBoxItem's IsEnabled property to the result of a Command's CanExecute method

China☆狼群 提交于 2019-12-06 04:22:36

You can put a button(if you dont have one in the controltemplate bound to the ICommand) inside ItemContainerStyle(ComboBoxItem style) and Bind the command to it And add a Trigger to check the Button.IsEnabled and set that value to the ComboBoxItem. So here we used Button as a CommandSource just to get the IsEnabled from CanExeute. You can set the button's height and width to zero

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

Another solution by ViewModel. Below is how I used a ViewModel to solve my problem. And please note that the nifty NotifyPropertyChanged method is part of my base ViewModel class.

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

I found this discussion on MSDN forums where Dr. WPF had recommended the use of an attached behavior to solve this exact problem. He gave the example below of how it would be used.

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

Although this solution seems pretty nice I haven't been able to devote the time to understand exactly how this type of behavior would be implemented and what is involved. If anybody would like to elaborate please do otherwise I'll amend this answer with more details if I get the chance to explore this option.

The way I solved this problem in my code was to add an event handler on the ComboBox for the PreviewMouseDown event. Here's the handler:

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

This works great for me in the case that I only need to do this in one location. It might get a little tedius if I had many pages like this.

Also, though I follow the MVVM pattern, I'm not a purist - I consider this to be a good practical solution that follows the spirit of MVVM, if not the letter.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!