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. Docker Remote API使用准备

    1 修改配置文件 CentOS: /etc/sysconfig/docker Ubuntu: /etc/init/docker.conf 1.添加: DOCKER_OPTS='-H tcp://0.0 ...

  2. 杨柳目-杨柳科-Info-新闻:让中国人焦虑的杨絮背后,隐藏着“拯救”北京的秘密!

    ylbtech-杨柳目-杨柳科-Info-新闻:让中国人焦虑的杨絮背后,隐藏着“拯救”北京的秘密! 1.返回顶部 1. 春天来了,北京和其他很多城市满城飞絮的日子也到了.库叔作为敏感体质,不得不戴上口 ...

  3. MySQL中使用LIMIT进行分页的方法

    一.分页需求: 客户端通过传递start(页码),pageSize(每页显示的条数)两个参数去分页查询数据库表中的数据,那我们知道MySql数据库提供了分页的函数limit m,n,但是该函数的用法和 ...

  4. 2019-8-31-C#-通过-probing-指定-dll-寻找文件夹

    title author date CreateTime categories C# 通过 probing 指定 dll 寻找文件夹 lindexi 2019-08-31 16:55:58 +0800 ...

  5. jmeter日期处理beanshell(2)

    import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Date;import java.text.P ...

  6. 04Redis入门指南笔记(内部编码规则简介)

    Redis是一个基于内存的数据库,所有的数据都存储在内存中.所以如何优化存储,减少内存空间占用是一个非常重要的话题.精简键名和键值是最直观的减少内存占用的方式,如将键名very.important.p ...

  7. Freeware Tools For Linux, http://www.debianhelp.co.uk/tools.htm

    Freeware Tools For Linux, http://www.debianhelp.co.uk/tools.htm Freeware Tools For Linux DNS related ...

  8. 可运行的js代码

    canrun <html> <head> <title>测试博客园HTML源码运行程序</title> <meta http-equiv=&quo ...

  9. Android Studio(四):Android Studio集成Genymotion

    Android Studio相关博客: Android Studio(一):介绍.安装.配置 Android Studio(二):快捷键设置.插件安装 Android Studio(三):设置Andr ...

  10. 【codeforces 520C】DNA Alignment

    [题目链接]:http://codeforces.com/contest/520/problem/C [题意] 给你一个函数; 它的作用是评估两个字符串的相似程度; 评估的时候: 保持一个字符串不动, ...