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. Leetcode804.Unique Morse Code Words唯一摩尔斯密码词

    国际摩尔斯密码定义一种标准编码方式,将每个字母对应于一个由一系列点和短线组成的字符串, 比如: "a" 对应 ".-", "b" 对应 &q ...

  2. Ubuntu 18.04中的Vim编辑器的高级配置

    VIM (Unix及类Unix系统文本编辑器) Vim是一个类似于Vi的著名的功能强大.高度可定制的文本编辑器,在Vi的基础上改进和增加了很多特性.VIM是开源软件. Vim普遍被推崇为类Vi编辑器中 ...

  3. Libevent:8Bufferevents高级主题

    本章描述的是Libevent的bufferevent实现的一些高级特性,这对于普通应用来说并非必须的.如果你只是学习如何使用bufferevent,则应该跳过本章去阅读evbuffer的章节. 一:成 ...

  4. Creating a Pulsing Circle Animation

    原文 https://www.kirupa.com/animations/creating_pulsing_circle_animation.htm Outside of transitions th ...

  5. 关于使用JavaMail发送邮件抛出java.lang.NoSuchMethodError: com.sun.mail.util.TraceInputStream.<init>(Ljava异常的解决方法

    我们在使用JavaMail时有可能会如下异常: Exception in thread "main" java.lang.NoSuchMethodError: com.sun.ma ...

  6. js+canvas黑白棋

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. 上传图片如何对图片进行压缩canvas

    前言:哈喽,朋友们,最近一直在马不停蹄地赶项目,很久没有写博客了.今天我们来看一下前端上传图片地时候如何对图片进行压缩 1.图片上传 我近期写项目都是使用的VUE,这里上传图片使用了Element-u ...

  8. 从开源小白到 Apache Member,我的成长之路

    我们走过的每一步路,都会留下印记,越坚实,越清晰. 近日,Apache 软件基金会(ASF)官方 Blog 宣布全球新增 40 位 Apache Member,张乎兴有幸成为其中一位. 目前,全球共有 ...

  9. celery 计划任务使用

    流程: 用户提交任务 --- > Celery --- > Broker 中间商(可以是数据库,redis) ---> 最后让celery 中的 worker 执行任务 1 单独使用 ...

  10. BERT大火却不懂Transformer?读这一篇就够了 原版 可视化机器学习 可视化神经网络 可视化深度学习

    https://jalammar.github.io/illustrated-transformer/ The Illustrated Transformer Discussions: Hacker ...