您的位置:首页 > 产品设计 > UI/UE

UIElementCollection

2015-08-20 09:57 399 查看
逻辑树:

逻辑树描述的是用户界面元素之间的关系,它主要负责:

传承依赖属性的值
设定动态资源的引用
为绑定查询元素的名称
传递路由事件

视图树:

视图树包括每一个逻辑元素的模板中的所有视图元素。它的责任是:

显示视图元素
设定元素的透明度
设定元素的布局和渲染变化
设定元素的可用(IsEnable)属性
做命中测试
关联资源(寻根)

Panel类的Childrend属性的类型是UIElementCollection

Panel类暴露了一个类型为UIElement的公有属性“Children”。Panel类重写了VisualChildrenCount属性和GetVisualChild()方法,将Children集合中的成员作为它的可视子元素返回。Panel也使用重写的GetVisualChild()方法为Children集合中的成员提供z-ordering。
public abstract class Panel : FrameworkElement, IAddChild
{
    ......
    private UIElementCollection _uiElementCollection;
    ......
    protected internal UIElementCollection InternalChildren
    {
	get
	{
	        this.VerifyBoundState();
	        if (this.IsItemsHost)
		{
			this.EnsureGenerator();
		}
		else if (this._uiElementCollection == null)
		{
			this.EnsureEmptyChildren(this);
		}
		return this._uiElementCollection;
	}
     }
      ......
      protected override int VisualChildrenCount
      {
	get
	{
		if (this._uiElementCollection == null)
		{
			return 0;
		}
		return this._uiElementCollection.Count;
	}
      }
      protected override Visual GetVisualChild(int index)
	{
		if (this._uiElementCollection == null)
		{
			throw new ArgumentOutOfRangeException("index", index, SR.Get("Visual_ArgumentOutOfRange"));
		}
		if (this.IsZStateDirty)
		{
			this.RecomputeZState();
		}
		int index2 = (this._zLut != null) ? this._zLut[index] : index;
		return this._uiElementCollection[index2];
	}
      protected virtual UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
	{
		return new UIElementCollection(this, logicalParent);
	}
}


UIElementCollection提供一种非常便捷的方式提供任何元素(可视元素或逻辑元素),不仅仅是面板。

一个元素可以简单地创建一个UIElementCollection的实例并将该元素自己作为集合的可视父元素。然后,任何被添加到集合的UIElement实例都将自动地被视为可视子元素添加到这个元素中。如果在创建集合的时候指定了一个逻辑元素,UIElement实例也会被视为逻辑子元素添加到这个元素中。

UIElementCollection的构造方法如下:
public UIElementCollection(UIElement visualParent, FrameworkElement logicalParent)

Panel类创建UIElementCollection的方法如下:
protected virtual UIElementCollection CreateUIElementCollection(FrameworkElement logicalParent)
{
    return new UIElementCollection(this, logicalParent);
}

从CreateUIElementCollection的实现可以看到,Panel将自身作为集合的可视父元素。因此在将UIElement添加到UIElementCollection中时,UIElementCollection内部会自动将该UIElement元素添加到以Panel作为可视父元素的可视树中,这样子元素就呈现出来了。
protected internal UIElementCollection InternalChildren
{
	get
	{
		this.VerifyBoundState();
		if (this.IsItemsHost)
		{
			this.EnsureGenerator();
		}
		else if (this._uiElementCollection == null)
		{
			this.EnsureEmptyChildren(this);
		}
		return this._uiElementCollection;
	}
}
<span style="color: #0000ff;  "><strong>internal</strong></span> <span style="color: #ff0000; ">void</span> <span style="color: #191970;  "><strong>EnsureGenerator</strong></span>()
{
    <span style="color: #0000ff;  "><strong>if</strong></span> (<span style="font-weight: bold; ">this</span>._itemContainerGenerator == <span style="font-weight: bold; ">null</span>)
    {
        <span style="font-weight: bold; ">this</span>.<span style="color: #191970;  "><strong>ConnectToGenerator</strong></span>();
        <span style="font-weight: bold; ">this</span>.<span style="color: #191970;  "><strong>EnsureEmptyChildren</strong></span>(<span style="font-weight: bold; ">null</span>);
        <span style="font-weight: bold; ">this</span>.<span style="color: #191970;  "><strong>GenerateChildren</strong></span>();
    }
}

可以看出如果Panel的IsItemsHost属性为true的话,UIElementCollection的logicalParent将为null。之所以设置为null是因为此时的LogicalParent应该是ItemsControl类或者它的子类型。如果按常规的方式使用Panel,则LogicalParent就是Panel自身,此时LogicalParent和VisualParent相同。

如果Panel的IsItemHost属性为true的话,UIElementCollection会阻止对内部集合的直接修改,只能通过ItemsControl间接地修改。不过UIElementCollection有一个后门允许在IsItemsHost为true的情况下修改内部的集合。这个方法就是通过与ItemsControl关联的ItemContainerGenerator来访问内部集合。

UIElementCollection将成员存储在内部的VisualCollection集合中。

UIElementCollection被创建时会在内部实例化一个VisualCollection类型的集合,这个集合才是真正设置可视父元素和存储Child的地方,同时这个集合还维护者可视父元素与Child之间的关系。UIElementCollection扩展了VisualCollection的功能,增加了维护逻辑父元素和Child之间关系的部分。
UIElementCollection在添加子元素时,如果LogicalParent不为null,会将子元素也添加到逻辑树中
public virtual UIElement this[int index]
{
	get
	{
		return this._visualChildren[index] as UIElement;
	}
	set
	{
		this.VerifyWriteAccess();
		this.ValidateElement(value);
		VisualCollection visualChildren = this._visualChildren;
		if (visualChildren[index] != value)
		{
			UIElement uIElement = visualChildren[index] as UIElement;
			if (uIElement != null)
			{
				this.ClearLogicalParent(uIElement);
			}
			visualChildren[index] = value;
			this.SetLogicalParent(value);
			this._visualParent.InvalidateMeasure();
		}
	}
}
<span style="color: #0000ff;  "><strong>protected</strong></span> <span style="color: #ff0000; ">void</span> <span style="color: #191970;  "><strong>SetLogicalParent</strong></span>(UIElement element)
{
    <span style="color: #0000ff;  "><strong>if</strong></span> (<span style="font-weight: bold; ">this</span>._logicalParent != <span style="font-weight: bold; ">null</span>)
    {
        <span style="font-weight: bold; ">this</span>._logicalParent.<span style="color: #191970;  "><strong>AddLogicalChild</strong></span>(element);
    }
}


UIElementCollection看上去是可以扩展的,因为它暴露了很多虚方法。此外Panel类也暴露了一个虚方法CreateUIElementCollection,我们可以重写这个方法来创建一个自定义的集合,这个集合必须继承自UIElementCollection。这个自定义集合还必须监听集合的改变,这可以通过重写一些方法:Add,Clear,Insert,Remove,RemoveAt等等。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: