如何为UserControl的XAML中的绑定提供默认值,以便Visual Studio能够正确地接收它?
我试图实现可重用的WPF UserControl,它使用DependencyProperties来自定义其行为,并且我在Visual Studio中遇到有关属性默认值的奇怪行为。
采取以下控制措施:
Widget.designer.cs
namespace WpfPropertiesTest
{
public partial class Widget : UserControl
{
public Widget()
{
InitializeComponent();
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register(nameof(Test), typeof(string), typeof(Widget),
new PropertyMetadata("Hello World"));
public string Test
{
get { return (string)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
}
}
Widget.xaml:
<UserControl x:Class="WpfPropertiesTest.Widget"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="_this">
<TextBlock Text="{Binding ElementName=_this, Path=Test, FallbackValue='Fallback', TargetNullValue='Null', Mode=OneWay}" />
</UserControl>
当我看到Widget.xaml的设计者时,我看到了回退值,这是合理的:
但是,我们现在可以在窗口中添加一个Widget:
// TestWindow.xaml
<Window x:Class="WpfPropertiesTest.TestWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfPropertiesTest"
Title="TestWindow" Height="100" Width="200">
<Grid>
<local:Widget />
</Grid>
</Window>
我希望看到其中一个&#34; Hello World&#34;,&#34; Fallback&#34;或&#34; Null&#34;,但实际得到的是:
......我绑定的属性名称是什么。
在运行时,使用相同的代码,我可以看到默认值:
现在,如果我明确设置属性的值:
<local:Widget Test="A value that I put in." />
设计师现在正确显示:
所有这些都告诉我,我的绑定是正确的,但Visual Studio(合理地)并没有实际查看代码隐藏中的依赖属性。当我实际对属性做某事时,例如绑定对它的可见性,这就成了一个问题。
那么,我错过了什么?有没有办法为Visual Studio提供在设计器中使用的值?我不希望每次使用它时都必须显式设置我的所有UserControl属性,并且我希望控件在设计器中的行为尽可能接近运行时。
我应该完全放弃绑定,只需在属性回调中设置代码隐藏值吗?
从更一般的意义上讲,这是否是制作可由消费者配置的可重用UserControl的正确方法?
答案 0 :(得分:0)
如果我没有弄错,那么这种行为的原因就是您在设计器中禁用了项目代码。要启用项目代码,请在设计器的底部切换最右边的按钮,从滚动条向左移动。
让我们做一个简单的实验。首先,让我们创建简单的测试类:
namespace Test
{
public class EmptyClass { }
}
然后让我们将这个 XAML 代码放入一些设计器的 XAML 控件中:
<Grid xmlns:test="clr-namespace:Test">
<Grid.Resources>
<ObjectDataProvider x:Key="Provider"
ObjectType="test:EmptyClass"
MethodName="GetType" />
</Grid.Resources>
<TextBlock Text="{Binding Source={StaticResource Provider}}" />
</Grid>
现在在设计器视图中,当启用项目代码时,我们会看到Test.EmptyClass
。但是,当禁用项目代码时,我们会看到Mocks.Test_EmptyClass_0_96752088
的内容。这得出结论,设计师使用生成的模拟类而不是实际的类(这是我所期望的 - 设计者不使用我的项目中的代码)。
我不知道生成模拟类的确切机制。也许没有调用mocked类的静态构造函数,或者mock类甚至不是从原始类派生的。无论哪种方式,分配默认属性元数据的代码都不会(也不应该)执行。