当前位置: 首页 > news >正文

WPF异步UI交互功能的实现方法

前面的文章我们提及过,异步UI的基础实现。基本思路主要是开启新的UI线程,并通过VisualTarget将UI线程上的Visual(即RootVisual)连接到主线程上的UI上即可渲染显示。

但是,之前的实现访问是没有交互能力的,视觉树上的UI并不能实现鼠标事件。那么今天我们就把交互的工作也给完成了。

实现交互能力的核心在于PresentationSource,它是完成交互功能的核心。它提供了交互源,它是一个抽象类,不能直接使用。我们需要通过继承它来实现交互逻辑。

具体代码如下:

 public class VisualTargetPresentationSource : PresentationSource{public VisualTargetPresentationSource(HostVisual hostVisual){_visualTarget = new VisualTarget(hostVisual);}public override Visual RootVisual{get{return _visualTarget.RootVisual;}set{Visual oldRoot = _visualTarget.RootVisual;_visualTarget.RootVisual = value;//此处是关键代码,通过根的时间通知,触发Load事件。通知视觉树,元素已经加载。//元素加载后,IsVisible会变成True,命中测试才能开始工作RootChanged(oldRoot, value);}}public override bool IsDisposed{get{return false;}}protected override CompositionTarget GetCompositionTargetCore(){return _visualTarget;}private VisualTarget _visualTarget;}

有了上述代码,我们的异步UI具备了交互能力。但是此时,我们用鼠标点击元素,依然是不会有动作发生的。

因为我们的UI是在异步线程上,它的功能受到一定的阉割,它并不能直接响应鼠标或者键盘事件。所以我们需要通过VisualHost来做路由事件的传递。

请看完整的示例:

//异步UI容器public class AsyncUIContainer : UIElement{public AsyncUIContainer(){Initialize();}private HostVisual hostVisual;private Grid RootVisual;private DispatcherUIThread dispatcherUIThread;/// <summary>/// /// </summary>private void Initialize(){hostVisual = new HostVisual();dispatcherUIThread = new DispatcherUIThread();dispatcherUIThread.Start();dispatcherUIThread.Dispatcher.Invoke(() =>{RootVisual = new Grid();new VisualTargetPresentationSource(hostVisual){RootVisual = RootVisual};});AddVisualChild(hostVisual);}public void UpdateRootLayout(Action<Grid> action){if (action != null){RootVisual.Dispatcher.Invoke(() =>{action(RootVisual);});}}#region overrideprivate UIElement _hitElement;protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters){RootVisual.Dispatcher.Invoke(() =>{_hitElement = (UIElement)RootVisual.InputHitTest(hitTestParameters.HitPoint);});if (_hitElement != null){return new PointHitTestResult(this, hitTestParameters.HitPoint);}else{return null;}}//此处是用来做路由事件转发,用于触发UI线程上的元素事件protected override void OnMouseDown(MouseButtonEventArgs e){base.OnMouseDown(e);if (_hitElement != null){_hitElement.Dispatcher.Invoke(() => _hitElement.RaiseEvent(e));}}//重写布局系统,让多线程UI元素能正常布局protected override Size MeasureCore(Size availableSize){if (availableSize.Height > 0 && availableSize.Width > 0 && !(double.IsInfinity(availableSize.Height) || double.IsInfinity(availableSize.Width))){RootVisual.Dispatcher.Invoke(() =>{RootVisual.Measure(availableSize);});return availableSize;}else{var minSize = new Size(200, 200);RootVisual.Dispatcher.Invoke(() =>{RootVisual.Measure(minSize);                  });return minSize;}}//重写布局系统,让多线程UI元素能正常布局protected override void ArrangeCore(Rect finalRect){base.ArrangeCore(finalRect);RootVisual.Dispatcher.Invoke(() =>{RootVisual.Arrange(finalRect);});RenderSize = finalRect.Size;}//指定起Visual的数量protected override int VisualChildrenCount => 1;//指定需要渲染的Visual对象protected override Visual GetVisualChild(int index){return hostVisual;}public void Dispose(){dispatcherUIThread?.Dispose();}#endregionpublic class VisualTargetPresentationSource : PresentationSource{public VisualTargetPresentationSource(HostVisual hostVisual){_visualTarget = new VisualTarget(hostVisual);}public override Visual RootVisual{get{return _visualTarget.RootVisual;}set{Visual oldRoot = _visualTarget.RootVisual;_visualTarget.RootVisual = value;RootChanged(oldRoot, value);}}public override bool IsDisposed{get{return false;}}protected override CompositionTarget GetCompositionTargetCore(){return _visualTarget;}private VisualTarget _visualTarget;}}

到这里,你就可以愉快的玩耍了。下期我们再实现异步UI在XAML上的编辑能力,可以在xaml中添加普通的xaml代码一样简单使用。


http://www.mrgr.cn/news/77841.html

相关文章:

  • SpringBoot中使用Sharding-JDBC实战(实战+版本兼容+Bug解决)
  • Vue 3组件间通信全解:选项式API vs 组合式API
  • Python的3D可视化库 - vedo (2)visual子模块 基本可视化行为
  • ElasticSearch学习篇18_《检索技术核心20讲》LevelDB设计思想
  • 谈谈Mysql的常见基础问题
  • “漫步北京”小程序及“气象景观数字化服务平台”上线啦
  • cangjie (仓颉) vscode环境搭建
  • .NET9 - 新功能体验(二)
  • 使用bcc/memleak定位C/C++应用的内存泄露问题
  • #Verilog HDL# 谈谈代码中如何跨层次引用
  • 下载安装Android Studio
  • #Verilog HDL# Verilog中的ifdef/ifndef/else等用法
  • 每日一练:位运算-消失的两个数字
  • CNN—LeNet:从0开始神经网络学习,实战MNIST和CIFAR10~
  • 第三十四篇 MobileNetV1、V2、V3模型解析
  • 【计算机网络】数据链路层
  • 算法(Algorithm)
  • Playwright(Java版) - 7: Playwright 页面对象模型(POM)
  • 使用 Spring Boot 和 GraalVM 的原生镜像
  • win10局域网加密共享设置
  • 《计算力学学报》
  • MCSA --- make coding simple again
  • JavaFX 实现文件夹和文件选择功能及常见问题解决方案
  • 动态规划子数组系列一>最长湍流子数组
  • 高频面试题(含笔试高频算法整理)基本总结回顾6
  • 【模块一】kubernetes容器编排进阶实战之pod的调度流程,pause容器及init容器