title author date CreateTime categories
WPF 跨线程 UI 的方法
lindexi
2018-10-18 10:25:28 +0800
2018-10-18 09:24:10 +0800
WPF

本文告诉大家如何在 WPF 使用多线程的 UI 的方法
在很多的时候都是使用单线程的 UI 但是有时候需要做到一个线程完全处理一个耗时的界面就需要将这个线程作为另一个 UI 线程

在 WPF 可以使用 VisualTarget 做到多个 UI 线程的绘制,注意这里的 WPF 的渲染线程只有一个,多个 UI 线程无法让渲染的速度加快。如果一个界面有很多的 Visual 那么渲染速度也不会因为添加 UI 线程用的时间比原来少

在 WPF 的 VisualTarget 可以用来连接多个不同的线程的 UI 元素,在使用的时候只需要创建,然后在另一个 UI 线程将创建的元素添加到 RootVisual 就可以

           var thread = new Thread(() =>
{
_visualTarget = new VisualTarget(xx); _visualTarget.RootVisual = 创建的 Visual;
});

创建一个 VisualTarget 需要用到 HostVisual 通过 HostVisual 可以在多个线程连到视觉树,所以创建 HostVisual 需要在主线程

public MainWindow()
{
InitializeComponent(); var hostVisual = new HostVisual(); var thread = new Thread(() =>
{
_visualTarget = new VisualTarget(hostVisual); _visualTarget.RootVisual = 创建的 Visual;
});
}

这时还需要将 hostVisual 加入视觉树,因为 HostVisual 也是 Visual 最简单将 Visual 加入视觉树的方法是创建一个类继承 UIElement 的方法,请看下面代码

    public class DispatcherContainer : UIElement
{
/// <inheritdoc />
protected override Visual GetVisualChild(int index)
{
return _hostVisual;
} /// <inheritdoc />
protected override int VisualChildrenCount => 1; private readonly HostVisual _hostVisual = new HostVisual();
}

然后在构造函数添加一个线程用来创建另一个 UI 线程,创建一个 UI 线程的最简单方法是运行 Dispatcher.Run() 和设置线程 STA 才可以,注意这里的 Dispatcher 是静态类

            var thread = new Thread(() =>
{ System.Windows.Threading.Dispatcher.Run();
}); thread.SetApartmentState(ApartmentState.STA);
thread.Start();

在这个线程里添加 VisualTarget 请看下面

            var thread = new Thread(() =>
{
_visualTarget = new VisualTarget(_hostVisual); _visualTarget.RootVisual = 创建的元素; System.Windows.Threading.Dispatcher.Run();
}); thread.SetApartmentState(ApartmentState.STA);
thread.Start();

下面创建一个简单的元素在另一个线程

            var thread = new Thread(() =>
{
_visualTarget = new VisualTarget(_hostVisual);
DrawingVisual drawingVisual = new DrawingVisual();
var drawing = drawingVisual.RenderOpen();
using (drawing)
{
var text = new FormattedText("欢迎访问我博客 http://lindexi.gitee.io 里面有大量 UWP WPF 博客",
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();

这时的 DispatcherContainer 类看起来是这样

    public class DispatcherContainer : UIElement
{
/// <inheritdoc />
public DispatcherContainer()
{
var thread = new Thread(() =>
{
_visualTarget = new VisualTarget(_hostVisual);
DrawingVisual drawingVisual = new DrawingVisual();
var drawing = drawingVisual.RenderOpen();
using (drawing)
{
var text = new FormattedText("欢迎访问我博客 http://lindexi.gitee.io 里面有大量 UWP WPF 博客",
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;
}

为了显示元素,需要添加到界面,打开界面添加下面代码

        <local:DispatcherContainer></local:DispatcherContainer>

运行可以看到下面界面,这里的文字是在另一个线程绘制,但是也是和主界面在相同的线程渲染

代码请看 https://github.com/lindexi/UWP/tree/master/wpf/CaitrairSodeyatarFowfurur

更多博客请看 WPF 同一窗口内的多线程 UI(VisualTarget) - walterlv

2018-10-18-WPF-跨线程-UI-的方法的更多相关文章

  1. [WinForm]WinForm跨线程UI操作常用控件类大全

    前言 在C#开发的WinForm窗体程序开发的时候,经常会使用多线程处理一些比较耗时之类的操作.不过会有一个问题:就是涉及到跨线程操作UI元素. 相信才开始接触的人一定会遇上这个问题. 为了解决这个问 ...

  2. WPF跨线程操作UI界面控件

       在WPF应用中,如果遇到多线程的需求时,如果引用WPF控件时会引发异常,异常内容:调用线程无法访问此对象,因为另一个线程拥有该对象.具体如下: 调用代码: ThreadcountThread= ...

  3. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作 (转)

    https://www.cnblogs.com/tommyheng/p/4104552.html 本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做de ...

  4. c#中Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧.       其实多线程 ...

  5. c#中多线程同步Lock(锁)的研究以及跨线程UI的操作

    本文只针对C#中,多线程同步所用到的锁(lock)作为研究对象.由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧. 其实多线程的同步,使用 ...

  6. 2018.10.18 bzoj1185: [HNOI2007]最小矩形覆盖(旋转卡壳)

    传送门 不难看出最后的矩形一定有一条边与凸包某条边重合. 因此先求出凸包,然后旋转卡壳求出当前最小矩形面积更新答案. 代码: #include<bits/stdc++.h> #define ...

  7. hard(2018.10.18)

    题意:给你一棵\(n\)个节点的树,\(q\)个询问,每次询问读入\(u,v,k,op\),需要满足树上有\(k\)对点的简单路径交都等于\(u,v\)之间的简单路径,\(op=1\)表示\(k\)对 ...

  8. cdq(2018.10.18)

    一句话题意:给你三个数列{a_i},{b_i},{c_i},保证每个数列都恰好是一个排列.你需要求出满足\(a_i<a_j,b_i<b_j,c_i<c_j\)的有序对\((i,j)\ ...

  9. 【2018.10.18】noip模拟赛Day2 地球危机(2018年第九届蓝桥杯C/C++A组省赛 三体攻击)

    题目描述 三体人将对地球发起攻击.为了抵御攻击,地球人派出了 $A × B × C$ 艘战舰,在太 空中排成一个 $A$ 层 $B$ 行 $C$ 列的立方体.其中,第 $i$ 层第 $j$ 行第 $k ...

  10. 2018.10.18 NOIP训练 01矩阵(组合数学)

    传送门 组合数学好题. 题目要求输出的结果成功把概率转化成了种类数. 本来可以枚举统计最小值为iii时的概率. 现在只需要统计最小值为iii时的方案数,每一行有不少于iii个1的方案数. 显然一行选i ...

随机推荐

  1. react-jd-index

    看见一些代码的产物,会觉得非常的漂亮~感谢无私开源的程序员们~你们是最可爱的人儿~~ //index.jsx require('./app/lib/common.css'); import React ...

  2. 洛谷P2062 分队问题

      这是一道普及/提高- 然后你懂的,贪心扫一遍就可以了. 不懂提交人数那么少. //Serene #include<algorithm> #include<iostream> ...

  3. NS2学习笔记

    这两天在调一个仿真程序,比较奇怪的错误,就是一个节点广播消息,在它通信半径内的节点收不到消息,一直在通信上找问题,找了半天也没找到. 最后,用gdb调试,发现在一个操作指针处发生了段错误,引起的原因时 ...

  4. controller接收前台数据—中文乱码问题

    项目用的开发环境为tomcat+eclipse+SSM 正如题目,controller接收前台数据-中文乱码问题,在页面编码为UTF-8的前提下,解决方案有二: 一) controller接收数据时, ...

  5. python 异常处理技巧

  6. 【错误收集】SVN冲突解决 标签: 错误收集 2016-03-13 08:44 624人阅读 评论(24) 收藏

    最近在倒代码,这真的是一件挺低效率的事情的,但是为了之后工作的进行,必须把这些已经做好的界面,做好的功能搬到新的框架上来,所以安排了10来个同学一起倒代码,因为大家共用一个解决方案,所以使用svn来进 ...

  7. 如何解决iOS内存错误

    由于iOS5.0之前没有自动应用计数机制,也没有Java那样的垃圾回收功能.我们都需要自己管理和控制对象的回收,这是一件很麻烦的事情,也是做iOS项目中最容易出现的问题.如果不掌握这些方法,调试这些问 ...

  8. LeetCode74 Search a 2D Matrix

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the follo ...

  9. 13 -1 BOM和定时器

    一 BOM JavaScript基础分为三个部分: ECMAScript:JavaScript的语法标准.包括变量.表达式.运算符.函数.if语句.for语句等. DOM:文档对象模型,操作网页上的元 ...

  10. dynamic_cast, static_cast, const_cast, reinterprt_cast浅析

    用法:dynamic_cast < type-id > ( expression ) 说明:Type-id必须是类的指针.类的引用或者void *:如果type-id是指针类型,那么exp ...