WPF的两棵树与绑定

时间:2021-09-26 01:27:33

原文:WPF的两棵树与绑定

 

先建立测试基类

public class VisualPanel : FrameworkElement
{
protected VisualCollection Children { get; set; } public VisualPanel()
{
Children = new VisualCollection(this);
} protected override int VisualChildrenCount
{
get
{
return Children.Count;
}
} protected override Visual GetVisualChild(int index)
{
return Children[index];
} protected override Size ArrangeOverride(Size finalSize)
{
if (VisualChildrenCount>0)
{
(Children[0] as FrameworkElement).Arrange(new Rect(0, 0, 100, 25));
}
return base.ArrangeOverride(finalSize);
}
}

添加元素,并将加入到Window窗体中

public class  VisualTest  : VisualPanel
{
public TextBlock textblock; private void TestVisual()
{
textblock = new TextBlock() { Text = "Hello", Background = Brushes.Red };
this.Children.Add(textblock);
} public VisualTest()
{
TestVisual();
}
}

效果

WPF的两棵树与绑定

视觉树绑定测试

//test1
textblock.SetBinding(TextBlock.TextProperty, new Binding("Title")
{
RelativeSource =
new RelativeSource() { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(Window) }
});
//test2
this.Tag = "Test";
textblock.SetBinding(TextBlock.TextProperty, new Binding("Tag")
{
RelativeSource =
new RelativeSource() { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(VisualTest) }
});

测试均通过

WPF的两棵树与绑定WPF的两棵树与绑定

使用ElementName绑定

//test3
this.Name = "VisualTest"; textblock.SetBinding(TextBlock.TextProperty, new Binding("Tag")
{
ElementName = this.Name
});

可以参考这里

http://www.cnblogs.com/Clingingboy/archive/2010/11/29/1891253.html

结果错误

WPF的两棵树与绑定

设置NameScope

this.Name = "VisualTest";
NameScope ns = new NameScope();
NameScope.SetNameScope(this, ns);
this.RegisterName(this.Name, this);
textblock.SetBinding(TextBlock.TextProperty, new Binding("Tag")
{
ElementName = this.Name
});

测试再次未通过

将元素添加到逻辑树当中

this.Name = "VisualTest";
NameScope ns = new NameScope();
NameScope.SetNameScope(this, ns);
this.RegisterName(this.Name, this);
AddLogicalChild(textblock);
textblock.SetBinding(TextBlock.TextProperty, new Binding("Tag")
{
ElementName = this.Name
});

测试通过

去除视觉树只添加逻辑树的情况

private void TestLogic()
{
textblock = new TextBlock() { Text = "Hello", Background = Brushes.Red };
this.Tag = "Test";
this.Name = "VisualTest";
NameScope ns = new NameScope();
NameScope.SetNameScope(this, ns);
this.RegisterName(this.Name, this);
AddLogicalChild(textblock);
textblock.SetBinding(TextBlock.TextProperty, new Binding("Tag")
{
ElementName = this.Name
});
}

现在UI将一片空白,但绑定成功

WPF的两棵树与绑定

重写ArrangeOverride方法

protected override Size ArrangeOverride(Size finalSize)
{
textblock.Arrange(new Rect(0, 0, 100, 25));
return base.ArrangeOverride(finalSize);
}

即使重写也无效,wpf依赖于VisualChildrenCount和GetVisualChild方法.

总结

绑定的ElementName依赖于NameScope和逻辑树,

FindAncestor的查找方式则依赖于视觉树

测试的父元素逻辑树与视觉树不一致的情况

private void TestTwoTree()
{
var visual = new VisualTest(string.Empty);
visual.Name = "InternalPanel";
textblock = new TextBlock() { Text = "Hello", Background = Brushes.Red };
visual.AddLogicalChild(textblock);
this.Children.Add(textblock);
}

现在TextBlock有两个父元素一个是逻辑父元素InternalPanel,一个是外部的VisualTest.

绑定逻辑父元素

private void TestTwoTree()
{
var visual = new VisualTest(string.Empty);
visual.Name = "InernalPanel";
NameScope ns = new NameScope();
NameScope.SetNameScope(visual, ns);
visual.RegisterName(visual.Name, visual);
textblock = new TextBlock() { Text = "Hello", Background = Brushes.Red };
textblock.SetBinding(TextBlock.TextProperty, new Binding("Name")
{
ElementName = visual.Name
});
visual.AddLogicalChild(textblock);
this.Children.Add(textblock);
}

测试结果

WPF的两棵树与绑定

这样就实现了可以在不同父元素的绑定,通过这个例子也可以看到逻辑树与视觉树的不同之处