WPF 从其他线程中修改更新控件

大家都知道,多线程可以大大提高WPF的反应效率,但是不幸的是,UI控件不能被多个线程同时更改。

比如:

代码
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();

CheckBox myCheckBox
= new CheckBox();
myCheckBox.Content
= "A Checkbox";

System.Threading.Thread thread
= new System.Threading.Thread(
new System.Threading.ThreadStart(
delegate()
{
txtUpdateDownloadInfo.Text
+= "update KB download begin...." + Environment.NewLine;
}
));

thread.Start();
}
}

则会抛出: The calling thread cannot access this object because a different thread owns it.的异常。

在Winform中我们可以是设置: Control.CheckForIllegalCrossThreadCalls = false; 在加上lock可以解决此问题,但是WPF中是没有这个属性的。

而幸运的是WPF同样提供了一个功能更大---Dispatcher。在WPF中大多数控件都是继承于DispacterObject,所以他们都具有Dispatcher属性。

所以,解决方案:

WPF:

代码
private void btnDownload_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(txtUpdates.Text))
{
MessageBox.Show(
"Error, Please input the update KBNumber");
return;
}
try
{
string[] updates = txtUpdates.Text.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in updates)
{
ParameterizedThreadStart st
= new ParameterizedThreadStart(Download);
Thread t
= new Thread(st);
t.Start(item);
}
}
catch (Exception ex)
{
MessageBox.Show(
"Error with :" + ex.Message);
}
}
public void Download(object Kbnumber)
{
CopyUpdates(Kbnumber
as string);
}
private void CopyUpdates(string p_updates)
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => txtUpdateDownloadInfo.Text += "update KB" + p_updates + " download begin...." + Environment.NewLine));


IEnumerable
<KeyValuePair<string, string>> updateLocations = new Dictionary<string, string>();

updateLocations
= updateLocations.Union(UpdatesSupport.GetUpdateSource(p_updates));

foreach (KeyValuePair<string, string> kvp in updateLocations)
{
try
{
if (!IO.Directory.Exists(IO.Path.GetDirectoryName(kvp.Value)))
IO.Directory.CreateDirectory(IO.Path.GetDirectoryName(kvp.Value));

if (!IO.File.Exists(kvp.Value) || IO.File.GetLastWriteTimeUtc(kvp.Value) < IO.File.GetLastWriteTimeUtc(kvp.Key))
IO.File.Copy(kvp.Key, kvp.Value);
}
catch
{ }
}

Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => txtUpdateDownloadInfo.Text += "update KB" + p_updates + " download completed...." + Environment.NewLine));


}

Winform:

代码
public UpdateInfos()
{
InitializeComponent();

DownloadPanel dp
= new DownloadPanel();
dp.Location
= new Point(9, 19);
gbxUIODT.Controls.Add(dp);

Control.CheckForIllegalCrossThreadCalls
= false;
}

private void btnUIDownload_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtUIUpdates.Text))
{
MessageBox.Show(
"Error, Please input the update KBNumber");
return;
}
try
{
string[] updates = txtUIUpdates.Text.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var item in updates)
{
ParameterizedThreadStart st
= new ParameterizedThreadStart(Download);
Thread t
= new Thread(st);
t.Start(item);
}
}
catch(Exception ex)
{
MessageBox.Show(
"Error with :" + ex.Message);
}

}

public void Download(object Kbnumber)
{
CopyUpdates(Kbnumber
as string);
}
public void CopyUpdates(string p_updates)
{
lock (this)
{
txtUIDonwloadInfo.Text
+= "update KB" + p_updates + " download begin...." + Environment.NewLine;
}
IEnumerable
<KeyValuePair<string, string>> updateLocations = new Dictionary<string, string>();

updateLocations
= updateLocations.Union(GetUpdateSource(p_updates));

foreach (KeyValuePair<string, string> kvp in updateLocations)
{
try
{
if (!Directory.Exists(Path.GetDirectoryName(kvp.Value)))
Directory.CreateDirectory(Path.GetDirectoryName(kvp.Value));

if (!File.Exists(kvp.Value) || File.GetLastWriteTimeUtc(kvp.Value) < File.GetLastWriteTimeUtc(kvp.Key))
File.Copy(kvp.Key, kvp.Value);
}
catch
{ }
}
lock (this)
{
txtUIDonwloadInfo.Text
+= "update KB" + p_updates + " download completed...." + Environment.NewLine;
}
}
原文地址:https://www.cnblogs.com/jimson/p/1925652.html