WPF:使用来自 c# 代码的自动绑定创建自定义按钮

WPF: Creating a custom button with automatic bindings from c# code

我有大量按钮具有基于键字符串的所有相同绑定架构。我想我可以通过制作一个接受该字符串并相应地设置所有绑定的自定义控件来节省一些代码重复。我想出了以下代码:

public class StateTransitionButton : Button
{
    public string StateTransition
    {
        get { return (string)this.GetValue(StateTransitionProperty); }
        set { this.SetValue(StateTransitionProperty, value); }
    }

    public static readonly DependencyProperty StateTransitionProperty =
        DependencyProperty.Register("MyProperty", typeof(string), typeof(StateTransitionButton), new PropertyMetadata(null, OnTransitionChanged));

    private static void OnTransitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is StateTransitionButton button && e.NewValue is string key)
        {
            button.CommandParameter = key;

            Binding commandBinding = new("ButtonClicked");
            commandBinding.Source = button.DataContext;
            _ = button.SetBinding(CommandProperty, commandBinding);
            button.CommandParameter = key;

            Binding visibilityBinding = new("CurrentState")
            {
                Converter = new UIStateToVisibilityConverter(),
                ConverterParameter = key
            };
            visibilityBinding.Source = button.DataContext;
            _ = button.SetBinding(VisibilityProperty, visibilityBinding);

            Binding tooltipBinding = new("CurrentState")
            {
                Converter = new UIStateToTooltipConverter(),
                ConverterParameter = key
            };
            tooltipBinding.Source = button.DataContext;
            _ = button.SetBinding(ToolTipProperty, tooltipBinding);
        }
    }
}

转换器已在旧代码中使用并按预期工作。在上面的代码中,绑定似乎没有正确设置。当我在 snoop 中检查它们时,命令绑定有一个错误(我从来没有想出如何从 snoop 获取可用的错误文本),可见性仍然具有默认值而不是绑定,并且工具提示 属性 不可检查。

更新:我在写完它的时候想到了这一点。无论如何我都会 post 它并自己回答它,因为我找不到任何关于如何在自定义控件内设置绑定的清晰示例,而其他人可能会发现我的解决方案很有用。如果我遗漏了更好的,请将其标记为重复。

原来是在数据上下文之前设置了 StateTransition 属性。这意味着所有绑定都绑定到 null。解决方法是侦听 DataContextChanged 事件并重新绑定。无论如何,即使原始代码有效,这也是更正确的,否则它不会处理数据上下文更改。

工作示例:

public class StateTransitionButton : Button
{
    public StateTransitionButton()
    {
        this.DataContextChanged += this.OnDataContextChanged;
    }

    public string StateTransition
    {
        get { return (string)this.GetValue(StateTransitionProperty); }
        set { this.SetValue(StateTransitionProperty, value); }
    }

    public static readonly DependencyProperty StateTransitionProperty =
        DependencyProperty.Register("MyProperty", typeof(string), typeof(StateTransitionButton), new PropertyMetadata(null, OnTransitionChanged));

    private static void OnTransitionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is StateTransitionButton button && e.NewValue is string key)
        {
            button.SetBindings(key);
        }
    }

    public void SetBindings(string key)
    {
        this.CommandParameter = key;

        Binding commandBinding = new("ButtonClicked");
        commandBinding.Source = this.DataContext;
        _ = this.SetBinding(CommandProperty, commandBinding);
        this.CommandParameter = key;

        Binding visibilityBinding = new("CurrentState")
        {
            Converter = new UIStateToVisibilityConverter(),
            ConverterParameter = key
        };
        visibilityBinding.Source = this.DataContext;
        _ = this.SetBinding(VisibilityProperty, visibilityBinding);

        Binding tooltipBinding = new("CurrentState")
        {
            Converter = new UIStateToTooltipConverter(),
            ConverterParameter = key
        };
        tooltipBinding.Source = this.DataContext;
        _ = this.SetBinding(ToolTipProperty, tooltipBinding);
    }

    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        this.SetBindings(this.StateTransition);
    }
}