1

我有一个复杂的窗口,其中包含基于布尔值可见或折叠的各种控件。我想添加一个自定义属性以在设计时显示所有这些控件。我的属性实现如下所示:

public static class CustomAttributes
{
    private static bool? _inDesignMode;

    public static readonly DependencyProperty Visibility = DependencyProperty.RegisterAttached(
        "Visibility",
        typeof(Visibility),
        typeof(CustomAttributes),
        new PropertyMetadata(VisibilityChanged));

    private static bool InDesignMode
    {
        get
        {
            if (!_inDesignMode.HasValue)
            {
                var prop = DesignerProperties.IsInDesignModeProperty;
                _inDesignMode =
                  (bool)DependencyPropertyDescriptor.FromProperty(prop, typeof(FrameworkElement)).Metadata.DefaultValue;
            }

            return _inDesignMode.Value;
        }
    }

    public static Visibility GetVisibility(DependencyObject dependencyObject)
    {
        return (Visibility)dependencyObject.GetValue(Visibility);
    }

    public static void SetVisibility(DependencyObject dependencyObject, Visibility value)
    {
        dependencyObject.SetValue(Visibility, value);
    }

    private static void VisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (!InDesignMode)
            return;

        d.SetValue(Control.VisibilityProperty, e.NewValue);
    }
}

在 XAML 中,我像这样使用它:

<Button Visibility="{Binding SomeBoolValue, Converter={StaticResource BoolToVisibility}}"
        helper:CustomAttributes.Visibility="Visible" 
/>

但是,它似乎不起作用。我使用了一些像这样的其他自定义属性,它们完成了它们的工作,但不会触发可见性,它只是在设计视图中保持折叠状态。我错过了什么?

编辑:

感谢您为我指明正确的方向。我的问题的解决方案不需要我最初假设的自定义属性。为了实现我想要的设计时行为,我按照下面接受的答案中的建议修改了转换器实现。

4

1 回答 1

1

更深入地思考您创建的逻辑。

UI 元素没有两个 Visibility 属性,它是唯一的一个。
但是您想同时以两种方式操作此属性:通过绑定和附加属性。
因此,您在他们之间为该属性创建了竞争。
并且该属性将采用最后分配给它的值。

初始化按钮时(来自示例),附加属性只会被触发一次。当数据上下文和/或其属性发生变化
时,将触发绑定。 但是 Window 的 Data Context 的设置要晚于这个 Window 的 UI 元素的初始化。SomeBoolValue

我看到了几种解决方案。
如果您需要始终在设计模式下显示元素,最简单的方法是向转换器添加适当的逻辑。
以最简单的形式,这种转换器的示例:

/// <summary>Bool to Visibility converter.</summary>
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BooleanToVisibilityConverter : IValueConverter
{
    public static bool IsDesignMode { get; } = DesignerProperties.GetIsInDesignMode(new DependencyObject());

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is bool val)
            return IsDesignMode || val 
                ? Visibility.Visible
                : Visibility.Collapsed;

        return DependencyProperty.UnsetValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
于 2021-05-27T05:58:37.127 回答