元素绑定到折叠的UserControl是一个邋,,廉价的伎俩?

时间:2010-03-03 22:10:33

标签: wpf xaml

我确信我们大多数人都会同意从自我上下文中用尽声明DataContext来源。然后我们可以求助于绑定到父Tag,然后使用元素绑定。因此源可能如下所示:

<Grid.Tag>
    <Binding Path="MyProperty" Source="{StaticResource MySource}" />
</Grid.Tag>

当我们甚至不能这样做时会发生什么?我的下一个草率技巧是使用折叠的UserControl元素:

<UserControl
    x:Name="MySloppyControl"
    DataContext="{StaticResource YetAnotherSourceInThisCrazyGrid}"
    Foreground={Binding CrazyForegroundColor}
    Visibility="Collapsed" />

现在我可以这样做:

<Grid.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Foreground" Value="{Binding CrazyForegroundColor, ElementName=MySloppyControl}" />
    </Style>
</Grid.Resources>

假设我已经充分解释了这个问题,这个崩溃的UserControl模式是否被误导了?

1 个答案:

答案 0 :(得分:3)

并非我自己没有这样做,但我不得不说“是” - 这种模式是错误的。

在我选择这样做的少数情况下,我的代码看起来像这样:

<Control x:Name="Whatever" DataContext="..." />
<Control x:Name="SomethingElse" DataContext="..." />

由于默认情况下控件不可见,因此使用较少的代码可以获得相同的效果。

话虽如此,让我解释为什么我认为这种做法是错误的:

WPF就是绑定数据。如果要绑定一些数据,它可以是模型(或视图模型)的一部分,也可以是外部数据。如果它是模型(或视图模型)的一部分,并且模型的结构定义良好,则应该能够通过当前的DataContext访问它。另一方面,如果它是静态的,您应该能够直接从目标访问它。

例如,假设您要使用模型中的所有可能的WidgetType填充ComboBox。如果您的模型构造良好,则绑定可以简单如下:

<ComboBox ItemsSource="{Binding DataSet.AllWidgetTypes}" />

这假设您的ComboBox的DataContext是“Widget”,并且“Widget”具有“DataSet”属性,可以访问其他相关数据。或者,如果可用类型列表可能会根据Widget的其他详细信息而更改,则绑定可能只是{Binding AppliableWidgetTypes}

在您调用它时可能需要“单独的DataContext”的另一种情况是引用静态对象时,例如通过x:Static或StaticResource。在这些情况下,有一种更好的方法:设置Binding.Source。它看起来像这样:

Text="{Binding DefaultFontSize,Source={x:Static ApplicationProperties.Instance}}"

或者

Text="{Binding PropertyName,Source={StaticResource ResourceContainingProperty}}"

如果你的动机是避免创建一个viewmodel来组合多个模型对象,那么使用C#anonymoust类型构建一个穷人的viewmodel。例如:

DataContext = new { something = 123, whatever = "Test" };

另一种常见模式是在控件上创建属性,并使用ControlTemplate和TemplateBinding绑定它们。

这留下了最后一种情况,即你真正想要一个共享值,而你根本不需要代码隐藏。在这种情况下,我实际上已经使用了前面显示的隐形<Control>。所以很少有情况可以适用。