WPF ToggleButton incorrect render behavior

togglebutton, wpf

Solution

That's my solution for the problem, here is the video, the usage:

<StackPanel>
    <ToggleButton x:Name="MyToggleButton" Content="MyToggleButton" Checked="MyToggleButton_Checked"
                    l:CorrectToggleButtonCheckedEnableBehavior.IsActive="True"/>
    <Button Name="EnableButton" Content="Enable" Click="EnableButton_Click"/>
</StackPanel>

and the attached behavior source code:

public static class CorrectToggleButtonCheckedEnableBehavior
{
    public static bool GetIsActive(ToggleButton toggleButton)
    {
        return (bool)toggleButton.GetValue(IsActiveProperty);
    }

    public static void SetIsActive(ToggleButton toggleButton, bool value)
    {
        toggleButton.SetValue(IsActiveProperty, value);
    }

    public static readonly DependencyProperty IsActiveProperty =
        DependencyProperty.RegisterAttached("IsActive", typeof(bool), typeof(CorrectToggleButtonCheckedEnableBehavior),
        new UIPropertyMetadata(false, OnIsActiveChanged));

    static void OnIsActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var toggleButton = (ToggleButton)d;

        if (GetIsActive(toggleButton))
        {
            toggleButton.IsEnabledChanged += new DependencyPropertyChangedEventHandler(ToggleButton_IsEnabledChanged);
        }
        else
        {
            toggleButton.IsEnabledChanged -= new DependencyPropertyChangedEventHandler(ToggleButton_IsEnabledChanged);
        }
    }

    static void ToggleButton_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var toggleButton = (ToggleButton)sender;

        if (toggleButton.IsEnabled && (toggleButton.IsChecked ?? false))
        {
            Invalidate(toggleButton);
        }
    }

    static void Invalidate(ToggleButton toggleButton)
    {
        var controlTemplate = toggleButton.Template;
        toggleButton.Template = null;
        toggleButton.Template = controlTemplate;
    }
}

Problem

What is going on here, and how to do a workaround? - Press MyToggleButton. Now it looks like instantly pressed (checked). - At the same time MyToggleButton_Checked handler disables the MyToggleButton. - Now press non-toggle Button 'Enable'. What we see? The MyToggleButton looks like it is enabled. OK. But wait, now it looks like non-pressed! Why?! XAML: ``` <StackPanel> <ToggleButton x:Name="MyToggleButton" Content="MyToggleButton" Checked="MyToggleButton_Checked"/> <TextBlock Text="{Binding IsChecked, ElementName=MyToggleButton}" Margin="0,4"/> <Button Name="EnableButton" Content="Enable" Click="EnableButton_Click"/> <Button Name="DisableButton" Content="Disable" Click="DisableButton_Click"/> </StackPanel> ``` Code-behind: ``` void MyToggleButton_Checked(object sender, RoutedEventArgs e) { MyToggleButton.IsEnabled = false; } void EnableButton_Click(object sender, RoutedEventArgs e) { MyToggleButton.IsEnabled = true; } void DisableButton_Click(object sender, RoutedEventArgs e) { MyToggleButton.IsEnabled = false; } ``` UPD: The only possible workaround on the moment is: ``` void EnableButton_Click(object sender, RoutedEventArgs e) { MyToggleButton.IsEnabled = true; var controlTemplate = MyToggleButton.Template; var buttonChrome = (Microsoft.Windows.Themes.ButtonChrome)controlTemplate.FindName("Chrome", MyToggleButton); buttonChrome.RenderPressed = false; buttonChrome.RenderPressed = true; } ``` Are there any others? UPD2: Another workaround is: ``` void EnableButton_Click(object sender, RoutedEventArgs e) { MyToggleButton.IsEnabled = true; var controlTemplate = MyToggleButton.Template; MyToggleButton.Template = null; MyToggleButton.Template = controlTemplate; } ``` But the control is flickering at the moment of template substitution.

Original source