WPF DataContext在看似相同的情况下的工作方式不同

时间:2016-10-16 15:04:08

标签: c# wpf data-binding datacontext

我有以下资源:

<Window.Resources>
    <SolidColorBrush x:Key="b" Color="{Binding B}" />
    <my:C x:Key="c" Prop="{Binding Source={StaticResource b}}" />
    <my:C x:Key="d" Prop="{Binding A}" />
    <Ellipse x:Key="e" Fill="{Binding A}" />
    <Ellipse x:Key="f">
        <Ellipse.Fill>
            <SolidColorBrush Color="{Binding B}" />
        </Ellipse.Fill>
    </Ellipse>
</Window.Resources>

我的窗口有一个声明如下的数据上下文:

<Window ... DataContext="{my:Context}" ...>

自定义类C和Context的定义如下:

public class Context : MarkupExtension
{
    public Brush A { get; } = Brushes.Blue;
    public Color B { get; } = Colors.Red;

    public override object ProvideValue(IServiceProvider serviceProvider) => this;
}

public class C : DependencyObject
{
    public static readonly DependencyProperty PropProperty = DependencyProperty.Register("Prop", typeof(Brush), typeof(C));
    public Brush Prop { get { return (Brush)GetValue(PropProperty); } set { SetValue(PropProperty, value); } }
}

现在,我使用数据上下文和绑定的方式看起来与我非常相似,但如果我使用以下代码检查我的资源(在按钮单击处理程序中)

MessageBox.Show("f: " + ((FindResource("f") as Ellipse).Fill?.ToString() ?? "null"));
MessageBox.Show("e: " + ((FindResource("e") as Ellipse).Fill?.ToString() ?? "null"));
MessageBox.Show("d: " + ((FindResource("d") as C).Prop?.ToString() ?? "null"));
MessageBox.Show("c: " + ((FindResource("c") as C).Prop?.ToString() ?? "null"));
MessageBox.Show("b: " + (FindResource("b") as SolidColorBrush).Color.ToString());

我得到了这个结果:

f: #00FFFFFF
e: null
d: null
c: #FFFF0000
b: #FFFF0000

即。只有最后两个看似正确。这可能是什么原因?

2 个答案:

答案 0 :(得分:1)

奇怪。

my:C显然没有DataContext,因此无法直接绑定到任何内容。

DataContext的资源不会继承资源所有者的DataContext(省略号e和f)

SolidColorBrush&#34; b&#34;派生形式System.Windows.Freezable,它有一个名为InheritanceContext的受保护字段/属性,用于&#34; b&#34;设置为MainWindow。我认为它可以通过这个引用访问Context.B,这就是为什么&#34; b&#34;和&#34; c&#34;显示正确的颜色。

答案 1 :(得分:0)

我对此很好奇,所以决定稍微玩一下。我远远不是XAML的专家,但我想分享我的发现,以防它有所帮助。

我在页面上的Grid添加了以下XAML:

<Ellipse Fill="{StaticResource b}" />
<Ellipse Grid.Row="1" Fill="{Binding Source={StaticResource c}, Path=Prop}" />
<Ellipse Grid.Row="2" Fill="{Binding Source={StaticResource d}, Path=Prop}" />
<ContentControl Grid.Row="3" Content="{StaticResource e}" />
<ContentControl Grid.Row="4" Content="{StaticResource f}" />

以下是结果的屏幕截图:

Ellipse Screenshot

“输出”窗口中出现以下绑定错误,我认为这解释了为什么d未填充:

  

System.Windows.Data错误:2:找不到管理FrameworkElement   或目标元素的FrameworkContentElement。   BindingExpression:路径= A;的DataItem = NULL;目标元素是&#39; C&#39;   (的HashCode = 60275915);目标财产是&#39; Prop&#39; (键入&#39;刷&#39;)

看起来它可能无法解析d的绑定,因为它无法在元素层次结构中找到它的位置,因此无法解析DataContext。

我还注意到,如果我对XAML进行了评论,其行为与问题中发布的完全相同。 ed都为空。基于此,似乎资源的使用可能会影响是否可以在运行时解析绑定。

如果能够更深入地了解绑定如何在资源中发挥作用的内部工作方式,那将会很棒。