很多小伙伴对“跨线程或跨类”使用WPF或WinFrom页面的控件不太明白,奉上一段小案例供参考(下面为WPF代码,WinFrom同理):
注:在WPF或WinFrom中,UI元素只能由其主线程来操作,其他任何线程都不可以直接操作UI,可以使用Dispatcher.Invoke(同步操作)或Dispatcher.BeginInvoke (异步操作)来操作。
1、xaml页面代码:
1 <Window
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6 xmlns:local="clr-namespace:WpfPaging"
7 xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" x:Class="WpfPaging.测试跨线程跨类调用控件"
8 mc:Ignorable="d"
9 Title="MainWindow" Height="700" Width="1000" Loaded="Window_Loaded">
10 <Grid>
11 <DataGrid HorizontalAlignment="Left" Height="623" Margin="10,10,0,0" VerticalAlignment="Top" Width="972" Name="dgtext" CanUserAddRows="True" AutoGenerateColumns="True">
12 <DataGrid.Columns>
13 <DataGridTextColumn Header="选中" Width="35" />
14 <DataGridTextColumn Header="公司名称" Width="80" Binding="{Binding 公司名称, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
15 <DataGridTextColumn Header="姓名" Width="80" Binding="{Binding 姓名, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
16 <DataGridTextColumn Header="年龄" Width="80" Binding="{Binding 年龄, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
17 <DataGridTextColumn Header="职务" Width="80" Binding="{Binding 职务, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
18 </DataGrid.Columns>
19 </DataGrid>
20 <Button Content="添加" HorizontalAlignment="Left" Margin="10,638,0,0" VerticalAlignment="Top" Width="75" Name="btnAdd" Click="BtnAdd_Click" RenderTransformOrigin="1.68,0.545"/>
21 <Button Content="保存" HorizontalAlignment="Left" Margin="121,638,0,0" VerticalAlignment="Top" Width="75" Name="btnSave" Click="btnSave_Click" RenderTransformOrigin="1.68,0.545"/>
22 <Button Content="删除" HorizontalAlignment="Left" Margin="236,638,0,0" VerticalAlignment="Top" Width="75" x:Name="btnDele" Click="btnDele_Click" RenderTransformOrigin="1.68,0.545"/>
23 <Button Content="跨线程调用控件" HorizontalAlignment="Left" Margin="334,638,0,0" VerticalAlignment="Top" Width="113" x:Name="btn1" Click="btn1_Click" RenderTransformOrigin="1.68,0.545"/>
24 <Button Content="跨类调用控件" HorizontalAlignment="Left" Margin="458,638,0,0" VerticalAlignment="Top" Width="97" x:Name="btn2" Click="btn2_Click" RenderTransformOrigin="1.68,0.545"/>
25 <Button Content="跨线程跨类调用控件" HorizontalAlignment="Left" Margin="566,638,0,0" VerticalAlignment="Top" Width="140" x:Name="btn3" Click="btn3_Click" RenderTransformOrigin="1.68,0.545"/>
26 </Grid>
27 </Window>
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
2、xaml.cs代码
1 using System.Collections.Generic;
2 using System.Threading;
3 using System.Windows;
4 using System.Windows.Threading;
5 using WpfPaging.NewFolder1;
6
7 namespace WpfPaging
8 {
9 // 声明一个委托
10 //public delegate void ChangeForm1TextBoxValue(string txt);
11 /// <summary>
12 /// MainWindow.xaml 的交互逻辑
13 /// </summary>
14 public partial class 测试跨线程跨类调用控件 : Window
15 {
16 #region 变量
17 // 委托事件
18 //public static event ChangeForm1TextBoxValue ChangeTextBoxValue;
19 #endregion
20
21 public 测试跨线程跨类调用控件()
22 {
23 InitializeComponent();
24 }
25
26 private void Window_Loaded(object sender, RoutedEventArgs e)
27 {
28 // 获取这些新添加的记录
29 List<Information> lstInformati = new List<Information>();
30 Information information = new Information();
31 information.公司名称 = "公司名称0";
32 information.姓名 = "姓名0";
33 information.年龄 = "年龄0";
34 information.职务 = "职务0";
35 lstInformati.Add(information);
36 dgtext.ItemsSource = lstInformati;
37 dgtext.Items.Refresh();
38 }
39 // 跨线程调用控件
40 private void btn1_Click(object sender, RoutedEventArgs e)
41 {
42 Thread t1 = new Thread(() =>
43 {
44 // 获取这些新添加的记录
45 List<Information> lstInformati = new List<Information>();
46 Information information = new Information();
47 information.公司名称 = "公司名称跨线程";
48 information.姓名 = "姓名跨线程";
49 information.年龄 = "年龄跨线程";
50 information.职务 = "职务跨线程";
51 lstInformati.Add(information);
52 Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
53 {
54 dgtext.ItemsSource = lstInformati;
55 dgtext.Items.Refresh();
56 });
57 })
58 {
59 IsBackground = true
60 };
61 t1.Start();
62 }
63 // 跨类调用控件
64 private void btn2_Click(object sender, RoutedEventArgs e)
65 {
66 TreadTest1 treadTest1 = new TreadTest1();
67 treadTest1.TestC(this.dgtext);
68 }
69 // 跨线程跨类调用控件
70 private void btn3_Click(object sender, RoutedEventArgs e)
71 {
72 Thread t1 = new Thread(TestITC);
73 t1.Start();
74 }
75
76 private void TestITC()
77 {
78 TreadTest1 treadTest1 = new TreadTest1();
79 treadTest1.TestITC( this.dgtext);
80 }
81 }
82 }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
3、调用类代码:
1 using System.Collections.Generic;
2 using System.Windows.Threading;
3 using System.Windows.Controls;
4 using System.Threading;
5
6 namespace WpfPaging.NewFolder1
7 {
8 声明一个委托
9 //public delegate void ChangeForm1TextBoxValue(string txt);
10 public class TreadTest1
11 {
12 委托事件
13 //public event ChangeForm1TextBoxValue ChangeTextBoxValue;
14 /// <summary>
15 /// 跨类调用控件
16 /// </summary>
17 internal void TestC(System.Windows.Controls.DataGrid dgtext)
18 {
19 // 获取这些新添加的记录
20 List<Information> lstInformati = new List<Information>();
21 Information information = new Information();
22 information.公司名称 = "公司名称 跨类";
23 information.姓名 = "姓名 跨类";
24 information.年龄 = "年龄 跨类";
25 information.职务 = "职务 跨类";
26 lstInformati.Add(information);
27 dgtext.ItemsSource = lstInformati;
28 dgtext.Items.Refresh();
29 }
30 /// <summary>
31 /// 跨线程跨类调用控件
32 /// </summary>
33 /// <param name="dgtext"></param>
34 internal void TestITC(DataGrid dgtext)
35 {
36 // 获取这些新添加的记录
37 List<Information> lstInformati = new List<Information>();
38 Information information = new Information();
39 information.公司名称 = "跨线程跨类调用控件";
40 information.姓名 = "跨线程跨类调用控件";
41 information.年龄 = "跨线程跨类调用控件";
42 information.职务 = "跨线程跨类调用控件";
43 lstInformati.Add(information);
44 dgtext.Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
45 {
46 dgtext.ItemsSource = lstInformati;
47 dgtext.Items.Refresh();
48 });
49 }
50 }
51 }
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
4、补充-Invoke推荐写法
Invoke方法将委托添加到UI线程的消息队列中,等待UI线程调用D执行。
在UI线程中应避免使用Invoke方法,防止出现额外的开销,针对这种情况我们可以使用控件.InvokeRequired进行判断。
#region WinFrom写法
private void UpdateUIControl(string text)
{
if (this.InvokeRequired) // 当前线程不是控件UI线程时为true
{
this.Invoke(new Action<string>(UpdateUIControl), text);
return;
}
this.label1.Text = text;
}
#endregion WinFrom写法
#region WPF写法
private void UpdateUIControl(string text)
{
if (this.Dispatcher.CheckAccess()) // 当前线程不是控件UI线程时为true
{
this.Dispatcher.Invoke(new Action<string>(UpdateUIControl), text);
return;
}
this.label1.Text = text;
}
#endregion WPF写法
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
5、关于Dispatcher.Invoke的理解请见下面的链接
(1)smallerpig的博客-Dispatcher.Invoke 方法
(2) 微软官方文档-Dispatcher 类
(3) 微软官方文档-Dispatcher.Invoke 方法
(4) 微软官方文档-Dispatcher.BeginInvoke 方法
6、线程与委托学习链接:
(1)线程学习笔记
(2)C#委托
(3)Thread类接收ThreadStart委托或ParameterizedThreadStart委托的构造函数的模板
作者:꧁执笔小白꧂