Search code examples
c#wpfdependency-properties

Update one Dependency Property based on another


I have a custom control I have set up in c#/wpf. I am using Dependency properties for items, some of these are optional, but my current code seems very convoluted:

public class PopupMenu : ContentControl
{
    public static readonly DependencyProperty AddWordCommandProperty =
        DependencyProperty.Register(nameof(AddWordCommand), typeof(ICommand), typeof(PopupMenu),
            new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnAddWordCommandChanged));
            
    public static readonly DependencyProperty ShowAddWordButtonProperty =
        DependencyProperty.Register(nameof(ShowAddWordButton), typeof(bool), typeof(PopupMenu),
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnShowAddWordButtonChanged));
            
    public ICommand AddWordCommand
    {
        get => (ICommand)GetValue(AddWordCommandProperty);
        set => SetValue(AddWordCommandProperty, value);
    }
    
    public bool ShowAddWordButton
    {
        get => (bool)GetValue(ShowAddWordButtonProperty);
        set => SetValue(ShowAddWordButtonProperty, value);
    }
    
    private static void OnAddWordCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not PopupMenu ctrl)
            return;

        ctrl.AddWordCommand = (ICommand)e.NewValue;
    }

    private static void OnShowAddWordButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not PopupMenu ctrl)
            return;

        ctrl.ShowAddWordButton = (bool)e.NewValue;
    }
}

When I use this control I must pass a command and also a bool for this button.

I have tried (and failed) ways of not having to pass the bool and instead letting 'ShowAddWordButton' be self-calculating, but is there a correct way to deal with this?

Attempt 1 - failed:

    public ICommand AddWordCommand
    {
        get => (ICommand)GetValue(AddWordCommandProperty);
        set
        {
            SetValue(AddWordCommandProperty, value);

            SetValue(ShowAddWordButtonProperty, value != null);
        }
    }

Attempt 2 - Failed:

    private static void OnAddWordCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is not PopupMenu ctrl)
            return;
            
        var cmd = (ICommand)e.NewValue;

        ctrl.AddWordCommand = cmd;
        
        ctrl.ShowAddWordButton = cmd != null;
    }

I have this code in place as this menu is going to grow with more buttons and they will not always be shown.

TIA


Solution

  • You haven't clearly stated what you want to get. I hope my guess is correct and this code will help you.

        public class PopupMenu : ContentControl
        {
            public static readonly DependencyProperty AddWordCommandProperty =
                DependencyProperty.Register(nameof(AddWordCommand), typeof(ICommand), typeof(PopupMenu),
                    new FrameworkPropertyMetadata(null,
                        (d,e)=> d.SetValue(ShowAddWordButtonPropertyKey, e.NewValue is not null)));
    
            private static readonly DependencyPropertyKey ShowAddWordButtonPropertyKey =
                DependencyProperty.RegisterReadOnly(nameof(ShowAddWordButton), typeof(bool), typeof(PopupMenu),
                    new FrameworkPropertyMetadata(false));
    
            public static readonly DependencyProperty ShowAddWordButtonProperty = ShowAddWordButtonPropertyKey.DependencyProperty;
    
            public ICommand AddWordCommand
            {
                get => (ICommand)GetValue(AddWordCommandProperty);
                set => SetValue(AddWordCommandProperty, value);
            }
    
            public bool ShowAddWordButton => (bool)GetValue(ShowAddWordButtonProperty);
        }
    
    

    Implementation option using style triggers:

    <Style TargetType="MenuItem">
        <Style.Triggers>
            <Trigger Property="Command" Value="{x:Null}">
               <Setter Property="Visibility" Value="Collapsed"/>
            </Trigger>
        </Style.Triggers>
    </Style>