Binding commands to ToggleButton Checked and Unchecked events
Asked Answered
F

4

16

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?

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

Floury answered 11/9, 2014 at 3:54 Comment(0)
R
7

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; }
    set
    {
        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

Reprobation answered 11/9, 2014 at 4:2 Comment(1)
I implemented it with Ineraction.Triggers. That just works perfectly! Its exactly what i need! thank you so much!Floury
S
31

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
    }
    else
    {
        //unchecked
    }
}

or perhaps you may pass it as a parameter too

eg

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

and use it as

void Execute(object state)
{
    if((bool)state)
    {
        //checked
    }
    else
    {
        //unchecked
    }
}
Selestina answered 11/9, 2014 at 4:55 Comment(0)
A
11

Maybe we can use EventTriggers

    <ToggleButton>
        <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"
Aland answered 11/9, 2014 at 5:4 Comment(2)
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!Floury
Glad you solved your problem, I'm sorry, didn't meant to double post, I didn't see the provided linkAland
R
7

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; }
    set
    {
        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

Reprobation answered 11/9, 2014 at 4:2 Comment(1)
I implemented it with Ineraction.Triggers. That just works perfectly! Its exactly what i need! thank you so much!Floury
K
-2
 <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.

Kildare answered 11/9, 2014 at 4:3 Comment(1)
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'."} .Floury

© 2022 - 2024 — McMap. All rights reserved.