WPF 具有跨线程功能的UI元素
概括
VisualTarget
本身继承自 CompositionTarget
,而不是 Visual
;其本身并不是可视化树的一部分。但是它的构造函数中可以传入一个 HostVisual
对象,这个对象是一个 Visual
,如果将此 HostVisual
放入原 UI 线程的可视化树上,那么 VisualTarget
就与主 UI 线程连接起来了。
另外一半,VisualTarget
需要连接另一个异步线程的可视化树。然而,VisualTarget
提供了 RootVisual
属性,直接给此属性赋一个后台 UI 控件作为其值,即连接了另一个 UI 线程的可视化树。
代码:
/// <summary>/// 此控件具有跨线程更新功能/// </summary>public class DispatcherContainer : UIElement{/// <inheritdoc />public DispatcherContainer(){ThreadUpdate();}public void ThreadUpdate(){var thread = new Thread(() =>{_visualTarget = new VisualTarget(_hostVisual);DrawingVisual drawingVisual = new DrawingVisual();var drawing = drawingVisual.RenderOpen();using (drawing){var text = new FormattedText("欢迎访问",CultureInfo.CurrentCulture, FlowDirection.LeftToRight,new Typeface(new FontFamily("微软雅黑"), new FontStyle(), FontWeight.FromOpenTypeWeight(1),FontStretch.FromOpenTypeStretch(1)), 20, Brushes.DarkSlateBlue);drawing.DrawText(text, new Point(100, 100));}var containerVisual = new ContainerVisual();containerVisual.Children.Add(drawingVisual);_visualTarget.RootVisual = containerVisual;System.Windows.Threading.Dispatcher.Run();});thread.SetApartmentState(ApartmentState.STA);thread.Start();}/// <inheritdoc />protected override Visual GetVisualChild(int index){return _hostVisual;}/// <inheritdoc />protected override int VisualChildrenCount => 1;private readonly HostVisual _hostVisual = new HostVisual();private VisualTarget _visualTarget;}
使用:
解释:
先理解Host 和 Root含义:
Host是宿主,Root是根基,大概是Root可以放在Host里面,Host是Root的载体的意思;
VisualTarget
的解释:提供跨线程边界将一个可视化树连接到另一个可视化树的功能。
拆分理解一下:提供了 跨线程的(副词) 连接可视化树(动词) 的功能。
简单理解为:可以跨线程拼接UI元素
与主线程连接:
上述控件的_hostVisual 字段属于主线程(UI 线程)的可视化树上,创建_visualTarget实例,把【DispatcherContainer 的_hostVisual 字段】赋值给【_visualTarget私有的_hostVisual字段】;
代码表现为:
_visualTarget = new VisualTarget(_hostVisual);
即_visualTarget通过关联了_hostVisual 间接的关联了UI线程;
与子线程连接:
//创建可视化对象,添加由DrawingVisual
绘制的内容
var containerVisual = new ContainerVisual();
containerVisual.Children.Add(drawingVisual);
//关联_visualTarget和子线程的可视化树
_visualTarget.RootVisual = containerVisual;
即_visualTarget通过关联了【子线程创建的containerVisual】间接的关联了子线程;
AI分析:
在 WPF 的 VisualTarget
中,_hostVisual
和 RootVisual
之间的关系是跨线程可视化的桥梁。让我详细解释它们的关系:
架构关系
主线程 (UI Thread) │ ├── HostVisual (_hostVisual) │ └── 作为占位符嵌入主可视化树 │ └── 通过 VisualTarget 连接到 ↓后台线程 (STA Thread) │ ├── VisualTarget (_visualTarget) │ └── 连接到主线程的 HostVisual │ └── RootVisual (容器视觉) │ └── 实际的可视化内容(文字、图形等)
详细关系说明
1. HostVisual (_hostVisual) - 主线程
-
角色:在主可视化树中的"占位符"或"代理"
-
位置:位于主 UI 线程的可视化树中
-
作用:为跨线程的可视化内容提供一个连接点
2. VisualTarget - 跨线程连接器
-
角色:连接不同线程间可视化树的桥梁
-
构造:
new VisualTarget(_hostVisual)
建立与 HostVisual 的连接 -
作用:管理线程间的可视化数据传递
3. RootVisual - 后台线程的根
-
角色:后台线程可视化树的根节点
-
位置:位于后台线程的可视化树中
-
作用:包含实际要显示的可视化内容
总结
其他文章展示的代码大同小异,思想就是一个HostVisual 对象 A 在主线程可视化树上,然后有一个子线程的UI对象B,然后A关联VisualTarget 对象的一个字段:_hostVisual ,B关联VisualTarget 对象的一个属性:RootVisual,实现B替换A的效果;
引用:
https://lindexi.blog.csdn.net/article/details/103184442?fromshare=blogdetail&sharetype=blogdetail&sharerId=103184442&sharerefer=PC&sharesource=qq_59062726&sharefrom=from_link
https://www.cnblogs.com/walterlv/p/10236528.html
https://blog.csdn.net/amanda_zhang2010/article/details/68946798?fromshare=blogdetail&sharetype=blogdetail&sharerId=68946798&sharerefer=PC&sharesource=qq_59062726&sharefrom=from_link
https://www.cnblogs.com/Zhouyongh/archive/2011/01/12/1933414.html
一点个人浅见,未必周全,权当抛砖引玉。若有疏漏之处,还请大家一起指正讨论。