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. List容器案例

    案例讲解 迭代模式 不暴露集合的内部结构,又让外部访问集合中的数据 package com.day1; public interface Iterator <T>{ public bool ...

  2. javaweb学习总结(一) - - JSP取得绝对路径

    在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况,常用的做法如下: 例如: 1 <!--使用绝对路径的方式引入 ...

  3. Android实战:手把手实现“捧腹网”APP(一)-----捧腹网网页分析、数据获取

    Android实战:手把手实现"捧腹网"APP(一)-–捧腹网网页分析.数据获取 Android实战:手把手实现"捧腹网"APP(二)-–捧腹APP原型设计.实 ...

  4. 【JZOJ4820】【NOIP2016提高A组模拟10.15】最大化

    题目描述 输入 输出 样例输入 3 2 4 0 -10 8 -2 -2 样例输出 4 数据范围 解法 枚举两条扫描线,在这两条扫描线之间的矩阵,可以将之转化为一个序列b[i]=a[i][1..m]. ...

  5. 洛谷P3455 [POI2007]ZAP-Queries (莫比乌斯反演)

    题意:求$\sum_{i=1}^{a}\sum_{j=1}^{b}[gcd(i,j)==d]$(1<=a,b,d<=50000). 很套路的莫比乌斯反演. $\sum_{i=1}^{n}\ ...

  6. python 浮点型(float)

  7. Java练习 SDUT-1132_斐波那契数列

    C/C++经典程序训练2---斐波那契数列 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 编写计算斐波那契(Fibon ...

  8. oracle函数 decode(条件,值1,翻译值1,值2,翻译值2,...值n,翻译值n,缺省值)

    [功能]根据条件返回相应值 [参数]c1, c2, ...,cn,字符型/数值型/日期型,必须类型相同或null 注:值1……n 不能为条件表达式,这种情况只能用case when then end解 ...

  9. How do I cover the “no results” text in UISearchDisplayController's searchResultTableView?

    How do I cover the "no results" text in UISearchDisplayController's searchResultTableView? ...

  10. html实体字符转换成字符串

    function EntityToString(value) { let tag = document.createElement("div"); tag.innerHTML = ...