相关文章推荐
深情的硬盘  ·  ASP.NET Core MVC ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have a ToggleButton in my C# WPF application where I would like to bind one Command to the Checked event and one Command to the Unchecked event.

What I have currently is the following:

<ToggleButton Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
              Checked="btnOpenPort_Checked" Unchecked="btnOpenPort_Unchecked"
              IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
              Canvas.Left="75" Canvas.Top="80" Height="25" Width="100"/>

But this is not what I aim to do. Because in this case, I would have to set properties in the code behind for the Checked and Unchecked event. Instead, I would like to call a Command (ICommand) in my ViewModel once the Checked or Unchecked event gets fired so that I don't need any code-behind for my toggle button.

Is there a way to bind a command directly for these two events in XAML? Similar to the command property of the "standard" button control in WPF?

This is how it works with regards to @har07 hint:

1: Added references if you dont have it yet:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"

2: Implemented Interaction.Triggers for Checked and Unchecked events:

<ToggleButton 
        Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
        IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
        Canvas.Left="75" Canvas.Top="80" Height="25" Width="100">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Checked">
                <i:InvokeCommandAction Command="{Binding Path=PortViewModel.OpenPort}"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="Unchecked">
                <i:InvokeCommandAction Command="{Binding Path=PortViewModel.ClosePort}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
</ToggleButton>

With this solution, I don't have to change a single line of code in my ViewModel or my code behind. I can just call my ICommand as I would do it with a standard button following MVVM pattern.

you may not be able to bind two commands for each checked and unchecked directly however you can still bind a command, which will be invoked for both. you also have option for attached behaviors if you need different command for both events.

<ToggleButton Command="{Binding MyCommand}"/>

in the vm

public ICommand MyCommand { get; private set; }

you will need to initialize it accordingly

and to determine the current state you may have a condition on the bonded property PortIsOpen

void Execute(object state)
    if(PortIsOpen)
        //checked
        //unchecked

or perhaps you may pass it as a parameter too

<ToggleButton Command="{Binding MyCommand}" 
              CommandParameter="{Binding IsChecked,RelativeSource={RelativeSource Self}}"/>

and use it as

void Execute(object state)
    if((bool)state)
        //checked
        //unchecked
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="Checked">
                <i:InvokeCommandAction Command="{Binding Path=CheckedCommand}"/>
            </i:EventTrigger>
            <i:EventTrigger EventName="Unchecked">
                <i:InvokeCommandAction Command="{Binding Path=UncheckedCommand}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </ToggleButton>

to use Triggers we have to reference System.Windows.Interactivity

 xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
                Thx, this is exactly what i did. @har07 s link refers exactly to that approach. i just updated my post few minutes ago to exactly that approach!
– ck84vi
                Sep 11, 2014 at 5:07
                Glad you solved your problem, I'm sorry, didn't meant to double post, I didn't see the provided link
– user3473830
                Sep 11, 2014 at 5:11

You can put the logic to handle checked/unchecked event in the setter of PortIsOpen property :

private bool _portIsOpen;
public bool PortIsOpen
    get { return _portIsOpen; }
        if(value) HandleCheckedEvent();
        else HandleUnCheckedEvent();

Or you can use Ineraction.Triggers extension to bind event to commmand : WPF Binding UI events to commands in ViewModel

I implemented it with Ineraction.Triggers. That just works perfectly! Its exactly what i need! thank you so much! – ck84vi Sep 11, 2014 at 4:54
 <ToggleButton Name="btnOpenPort" Style="{StaticResource myOnOffBtnStyle}" Content="Open Port"
              Checked="{Binding ICommand}"  Unchecked="{Binding ICommand}"
              IsChecked="{Binding Path=PortViewModel.PortIsOpen, Mode=OneWay}"
              Canvas.Left="75" Canvas.Top="80" Height="25" Width="100"/>

Replace ICommand with your ICommand property name.

This approach throws an XamlParseException - 'Provide value on 'System.Windows.Data.Binding' threw an exception.'- pointing to the line where i Bind the ICommand. {"Unable to cast object of type 'System.Reflection.RuntimeEventInfo' to type 'System.Reflection.MethodInfo'."} . – ck84vi Sep 11, 2014 at 4:17

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.