代码改变世界

WPF的两棵树与绑定

  Clingingboy  阅读(1557)  评论(0编辑  收藏  举报

 

先建立测试基类

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();
    }
}

效果

image

视觉树绑定测试

//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) }
});

测试均通过
imageimage

使用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

结果错误

image

设置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将一片空白,但绑定成功

image

重写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);
}

测试结果

image

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

编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示