惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
Darknet – Hacking Tools, Hacker News & Cyber Security
V
Vulnerabilities – Threatpost
Cloudbric
Cloudbric
G
GRAHAM CLULEY
S
Securelist
Schneier on Security
Schneier on Security
Help Net Security
Help Net Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Project Zero
Project Zero
Spread Privacy
Spread Privacy
P
Privacy International News Feed
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
T
Tailwind CSS Blog
博客园_首页
有赞技术团队
有赞技术团队
Simon Willison's Weblog
Simon Willison's Weblog
Stack Overflow Blog
Stack Overflow Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Latest news
Latest news
T
Tor Project blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Attack and Defense Labs
Attack and Defense Labs
www.infosecurity-magazine.com
www.infosecurity-magazine.com
O
OpenAI News
J
Java Code Geeks
T
Tenable Blog
K
Kaspersky official blog
AWS News Blog
AWS News Blog
S
Security @ Cisco Blogs
The GitHub Blog
The GitHub Blog
T
Threatpost
月光博客
月光博客
H
Heimdal Security Blog
Security Latest
Security Latest
The Hacker News
The Hacker News
Y
Y Combinator Blog
A
Arctic Wolf
Apple Machine Learning Research
Apple Machine Learning Research
C
Cisco Blogs
美团技术团队
Microsoft Security Blog
Microsoft Security Blog
Hugging Face - Blog
Hugging Face - Blog
T
The Blog of Author Tim Ferriss
C
CERT Recently Published Vulnerability Notes
D
Docker
Google Online Security Blog
Google Online Security Blog
D
DataBreaches.Net
V
Visual Studio Blog
H
Help Net Security

博客园 - idior

每日代码 - 7/1 减小方法参数的依赖 每日代码 - 6/29 读写分离 每日代码 - 6/28 代码逻辑分组 每日代码 - 6/26 lambda表达式 每日代码 - 6/27 避免创建非法对象 Resume Covariance and Contravariance How does ElementName Binding work? How does ElementName Binding work – Part 3 InheritanceContext How does ElementName Binding work – Part 2 BindingExpression Logical Tree & Visual Tree Memory leak caused by EventHandle - weak event Resources on Debugging/Tracing WPF How does ElementName Binding work? - Part 1 Logical Tree & NameScope Inside WCF Runtime 有谁准备参加10月份的MVP聚会? MVP聚会 Practical .NET2 and C#2 翻译样章 Be evil or not?
Weird behavior of DataContext Inheritance
idior · 2010-06-13 · via 博客园 - idior

Actually there are several questions in this post, though all of them are about DataContext inheritance. I think you will have have fun with these questions, if anyone can explain what's going on here, it will be greatly appreciated, however it's really not that easy to answer.

I created a CustomControl which derives from ContentControl by adding a Gutter property, so that the user of this control can specify two part of this control Content and Gutter. Here is my codes:

public class BizField : ContentControl
   {
       static BizField()
       {
           DefaultStyleKeyProperty.OverrideMetadata(typeof(BizField), new FrameworkPropertyMetadata(typeof(BizField)));
       }

       public object Gutter
       {
           get { return (object)GetValue(GutterProperty); }
           set { SetValue(GutterProperty, value); }
       }

       // Using a DependencyProperty as the backing store for Gutter.  This enables animation, styling, binding, etc...
       public static readonly DependencyProperty GutterProperty =
           DependencyProperty.Register("Gutter",
                           typeof(object), 
                           typeof(BizField), 
                           new UIPropertyMetadata(null,
                               new PropertyChangedCallback(OnGutterChanged)));


       private static void OnGutterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           var me = sender as BizField;
           me.OnGutterChanged(e);
       }

       private void OnGutterChanged(DependencyPropertyChangedEventArgs e)
       {
         
       }
   }

The template is quite simple:

    <Style TargetType="{x:Type local:BizField}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:BizField}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <StackPanel>
                            <ContentPresenter/>
                            <ContentPresenter ContentSource="Gutter"/>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Now if I use it in the main window, it works as expected:

<Window x:Class="DataContexPropagate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataContexPropagate"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:BizField>
            <Button Content="Click one"/>
            <local:BizField.Gutter>
                <Button Content="{Binding}"/>
            </local:BizField.Gutter>
        </local:BizField>
    </Grid>
</Window>

public partial class MainWindow : Window
  {
      public MainWindow()
      {
          //Notice DataContext is set before parsing the baml
          this.DataContext = "Hello";       
          InitializeComponent();
         
      }
  }

The button defined in the Gutter shows  "Hello". Now I try to add the gutter as BizField's logical child.

    private void OnGutterChanged(DependencyPropertyChangedEventArgs e)
   {
      this.AddLogicalChild(Gutter);
   }

It still works fine, but if I set the DataContext after loading xaml, it will broke.

public partial class MainWindow : Window
{
    public MainWindow()
    {             
        InitializeComponent();
        //Set datacontext after parsing baml
        this.DataContext = "Hello";
       
    }
}

If you run the application, the button show nothing, apparently DataContext Inheritance doesn’t work properly now. But if i change the button to a TextBlock, it will work. What’s the magic with TextBlock?

<Window x:Class="DataContexPropagate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataContexPropagate"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:BizField>
            <Button Content="Click one"/>
            <local:BizField.Gutter>
                <TextBlock Text="{Binding}"/>
            </local:BizField.Gutter>
        </local:BizField>
    </Grid>
</Window>

To make the databinding works for the button, i have to add following codes to BizControl.

protected override System.Collections.IEnumerator LogicalChildren
     {
         get
         {
             yield return Content;
             yield return Gutter;
         }
     }

According to this example, you will find that "setting datacontext before or after parsing Baml does matter".  But i don't why and more intersting what happened to the TextBlock?

Full source codes for BizField:

public class BizField : ContentControl
   {
       static BizField()
       {
           DefaultStyleKeyProperty.OverrideMetadata(typeof(BizField), new FrameworkPropertyMetadata(typeof(BizField)));
       }



       public object Gutter
       {
           get { return (object)GetValue(GutterProperty); }
           set { SetValue(GutterProperty, value); }
       }

       // Using a DependencyProperty as the backing store for Gutter.  This enables animation, styling, binding, etc...
       public static readonly DependencyProperty GutterProperty =
           DependencyProperty.Register("Gutter",
                           typeof(object),
                           typeof(BizField),
                           new UIPropertyMetadata(null,
                               new PropertyChangedCallback(OnGutterChanged)));


       private static void OnGutterChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
       {
           var me = sender as BizField;
           me.OnGutterChanged(e);
       }

       private void OnGutterChanged(DependencyPropertyChangedEventArgs e)
       {
           //Comment this out, it will search for the visual parent.
           this.AddLogicalChild(Gutter);
       }

       //Only by adding this method, it can work properly.
       protected override System.Collections.IEnumerator LogicalChildren
       {
           get
           {
               yield return Content;
               yield return Gutter;
           }
       }
   }
 
 
<Window x:Class="DataContexPropagate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataContexPropagate"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <local:BizField>
            <Button Content="Click one"/>
            <local:BizField.Gutter>
                <Button Content="{Binding}"/>
                <!--<TextBlock Text="{Binding}"/>-->
            </local:BizField.Gutter>
        </local:BizField>
    </Grid>
</Window>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        //Notice DataContext is set before parsing the baml
        //this.DataContext = "Hello";        
        InitializeComponent();
        //Set datacontext after parsing baml
        this.DataContext = "Hello";
       
    }
}