WPF 中的自定义设计时可见性属性
Custom design time visibility attribute in WPF
我有一个复杂的 window,其中包含基于布尔值显示或折叠的各种控件。我想添加一个自定义属性以在设计时显示所有这些控件。
我对该属性的实现如下所示:
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"
/>
不过,好像不行。我像这样使用其他一些自定义属性,它们完成了它们的工作,但不会触发可见性,它只是在设计视图中保持折叠状态。我错过了什么?
编辑:
感谢您为我指明了正确的方向。我的问题的解决方案并不像我最初假设的那样需要自定义属性。为了实现我想要的设计时行为,我按照下面接受的答案中的建议修改了转换器实现。
更深入地思考您创建的逻辑。
UI 元素没有两个可见性属性,它是唯一的一个。
但是您想同时以两种方式操作此 属性:通过绑定和附加的 属性.
因此,你在他们之间制造了竞争 属性.
属性 将采用最后分配给它的值。
附加的属性只会在按钮初始化时触发一次(来自示例)。
当数据上下文 and/or 其 SomeBoolValue
属性 更改时将触发绑定。
但是 Window 的数据上下文设置晚于此 Window.
的 UI 元素的初始化
我看到了几个解决方案。
如果您需要始终在设计模式中显示元素,最简单的方法是向转换器添加适当的逻辑。
这种转换器的最简单形式的示例:
/// <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();
}
}
我有一个复杂的 window,其中包含基于布尔值显示或折叠的各种控件。我想添加一个自定义属性以在设计时显示所有这些控件。 我对该属性的实现如下所示:
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"
/>
不过,好像不行。我像这样使用其他一些自定义属性,它们完成了它们的工作,但不会触发可见性,它只是在设计视图中保持折叠状态。我错过了什么?
编辑:
感谢您为我指明了正确的方向。我的问题的解决方案并不像我最初假设的那样需要自定义属性。为了实现我想要的设计时行为,我按照下面接受的答案中的建议修改了转换器实现。
更深入地思考您创建的逻辑。
UI 元素没有两个可见性属性,它是唯一的一个。
但是您想同时以两种方式操作此 属性:通过绑定和附加的 属性.
因此,你在他们之间制造了竞争 属性.
属性 将采用最后分配给它的值。
附加的属性只会在按钮初始化时触发一次(来自示例)。
当数据上下文 and/or 其 SomeBoolValue
属性 更改时将触发绑定。
但是 Window 的数据上下文设置晚于此 Window.
我看到了几个解决方案。
如果您需要始终在设计模式中显示元素,最简单的方法是向转换器添加适当的逻辑。
这种转换器的最简单形式的示例:
/// <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();
}
}