Enable a child control when the parent is disabled
Asked Answered
A

2

8

I have a Button containing a Hyperlink, like so:

<Button IsEnabled="False">
    <Hyperlink IsEnabled="True">Testing</Hyperlink>
</Button>

I need the Hyperlink to be enabled, however the Button to be disabled. How can I achieve this?

The above simply results in both controls being disabled.

Aphaeresis answered 29/1, 2013 at 13:56 Comment(2)
What is the purpose of having a hyperlink inside a button?Tamratamsky
@AbZy The hyperlink shows meta-information about the other content in the button (which I have omitted for brevity). I still want the user to be able to access that meta-information even if the button itself is disabled.Aphaeresis
K
5

I solved this problem by creating a simple wrapper element that breaks the IsEnabled inheritance chain from the parent.

The framework's default coerce callback checks the parent IsEnabled value and inherits it. This control sets a new coerce callback that just returns the value directly without checking inheritance.

public class ResetIsEnabled : ContentControl
{
    static ResetIsEnabled()
    {
        IsEnabledProperty.OverrideMetadata(
            typeof(ResetIsEnabled),
            new UIPropertyMetadata(
                defaultValue: true,
                propertyChangedCallback: (_, __) => { },
                coerceValueCallback: (_, x) => x));
    }
}

In the example from the question it would be used like this:

<Button IsEnabled="False">
  <ResetIsEnabled>
    <!-- Child elements within ResetIsEnabled have IsEnabled set to true (the default value) -->
    <Hyperlink>Testing</Hyperlink>
  </ResetIsEnabled>
</Button>
Kriss answered 23/6, 2021 at 19:59 Comment(1)
Simple and effective solution!Godbeare
E
0

Control Hyperlink has strangely with the property IsEnabled. In addition to the one that you mentioned, namely, the full value inheritance from a parent, there is another similar.

Hyperlink for the specific control, which has been turned off (IsEnabled="False"), setting (IsEnabled="True") will not update the Hyperlink property. The solution - use a relative source for Hyperlink (more info).

For solving your question, I have decided that it is not the standard way to solve. So I created a Class with its own dependencies properties. It has it's property MyIsEnabled and MyStyle. As you might guess from the title, the first sets its property IsEnabled and MyStyle need to specify the button style, simulating the IsEnabled="False" behavior.

SimulateDisable Style

<Style x:Key="SimulateDisable" TargetType="{x:Type Button}">
    <Setter Property="Opacity" Value="0.5" />
    <Setter Property="Background" Value="Gainsboro" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border CornerRadius="4" BorderThickness="1" BorderBrush="DarkBlue" SnapsToDevicePixels="True">
                    <ContentPresenter x:Name="MyContentPresenter" Content="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Define Button with yours properties:

<Button Name="MyButton" local:MyClass.MyIsEnabled="False" local:MyClass.MyStyle="{StaticResource SimulateDisable}" Width="100" Height="30" Click="Button_Click">
    <Hyperlink IsEnabled="True" Click="Hyperlink_Click">Testing</Hyperlink>
</Button>      

Listing of MyClass

public class MyClass : DependencyObject
{
    public static readonly DependencyProperty MyIsEnabledProperty;

    public static readonly DependencyProperty MyStyleProperty;

    #region MyIsEnabled

    public static void SetMyIsEnabled(DependencyObject DepObject, bool value)
    {
        DepObject.SetValue(MyIsEnabledProperty, value);
    }

    public static bool GetMyIsEnabled(DependencyObject DepObject)
    {
        return (bool)DepObject.GetValue(MyIsEnabledProperty);
    }

    #endregion MyIsEnabled

    #region MyStyle

    public static void SetMyStyle(DependencyObject DepObject, Style value)
    {
        DepObject.SetValue(MyStyleProperty, value);
    }

    public static Style GetMyStyle(DependencyObject DepObject)
    {
        return (Style)DepObject.GetValue(MyStyleProperty);
    }

    #endregion MyStyle

    static MyClass()
    {
        MyIsEnabledProperty = DependencyProperty.RegisterAttached("MyIsEnabled",
                              typeof(bool),
                              typeof(MyClass),
                              new UIPropertyMetadata(false, OnPropertyChanged));

        MyStyleProperty = DependencyProperty.RegisterAttached("MyStyle",
                          typeof(Style),
                          typeof(MyClass),
                          new UIPropertyMetadata(OnPropertyChanged));
    }

    private static void OnPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        Button MyButton = sender as Button;
        bool MyBool = GetMyIsEnabled(MyButton);

        if (MyBool == false)
        {
            MyButton.Style = MyClass.GetMyStyle(MyButton);
        }            
    }
}

Plus for the event Hyperlink pointing e.Handled = true, so that the event did not happen next.

private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Hyperlink Click!");

    e.Handled = true;
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Button Click! Don't show it's!");
}      

Output

enter image description here

P.S. Sorry for late answer :).

Emphatic answered 15/7, 2013 at 16:26 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.