Search code examples
c#mvvmbindingtogglebuttonischecked

C# MVVM Toggle button IsChecked binding


My MVVM code requires hooking up a WPF Toggle button to a ViewModel.

The requirement is that when the Toggle button is 'Clicked' it executes the bound command changing the IsConnected property (bool). This property should define the visual state of thee toggle button.

What actually happens once I click the toggle button, it fires the bound command but irrespective of the IsConnected property value it changes its visual state to checked. What I want is the visual state of the toggle button to be dependent on the IsConnected property.

How can I avoid this race condition or prevent the Checked event from firing?

The XAML code is:

<ToggleButton Name="btnConnect"
              DataContext="{Binding someViewModel, Source={StaticResource Locator}}"
              IsChecked="{Binding Path=IsConnected, Mode=OneWay}"
              Command="{Binding ConnectCommand}">        
    
</ToggleButton>

Snapshot of the ViewModel:

    public someViewModel()
    {
        Task.Factory.StartNew(() => Initialize());
    }

    public bool IsConnected
    {
        get
        {
            return m_bConnected;
        }
        set
        {
            Set<bool>(() => this.Connected, ref m_bConnected, value);
        }
    } 

    private void Initialize()
    {
        // Init Motion controller connection
        ConnectCommand = new RelayCommand(ConnectMethod);
    }

    public RelayCommand ConnectCommand
    {
        get;
        private set;
    }

    public void ConnectMethod()
    {
        try
        {
            // When in simulation mode
            //m_API.OpenCommSimulator();
            m_API.OpenCommEthernet("192.168.0.139", 731);
            if (m_API.IsConnected)
                Connected = true;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "CONNECTION ERROR", MessageBoxButton.OK, MessageBoxImage.Error);
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }

Solution

  • I ran into the same problem and found a simple solution:

    Since we are binding a command to react when a user clicks on the Togglebutton in this scenario, we have all we need. Just raise a PropertyChanged Event for the property bound to IsChecked. In your case you should raise the event for Isconnected and this would be the first thing to do in your ConnectMethod. This ensures that Togglebutton stays in the state until the property realy changes.

    Explanation: This works because the change is only made on the visual state and the underlying property is not changed as expected for OneWay Binding. Thus the property has still it's unchanged value and with raising the PropertyChanged Event the Togglebutton is forced to sync it's visual state with the value of the property and keep its state. When the property gets changed for real the PropertyChanged Event is automatically raised again and the Togglebutton can finally change its state as wished.

    Hopefully this answer helps others running into this problem and searching for a solution