C# - 如何从另一个 class 中的线程更新 Main UI
C# - How to update Main UI from a thread in another class
我实际上正在学习(艰难地)c# 并且一直在为一个问题而奋斗:
我正在使用 WPF (dotNet 4.0) 编写我的第一个 c# 应用程序。当我单击一个按钮时,会使用一个 BackgroundWorker 线程并从外部 class 调用一个方法,这样我的 UI 就不会冻结 -> 我的方法 运行 如预期的那样。
然后我尝试从那些外部 class 更新 ListView 控件以获得某种进展(文本),但我悲惨地失败了。
我知道我需要使用委托和调度程序来更新我的控件。
我尝试使用此处提供的解决方案 How to update UI from another thread running in another class。 (由于我的代表率低,我无法对此发表评论)并且我错过了拼图的某些部分。
YourEventArgs(status) 指的是什么?我只是不知道触发事件并将内容传回我的 UI 的方法,而我的方法是 运行 在 BGW 中。
到目前为止我有这段代码(更新自答案):
namespace AppMain
{
public partial class MainWindow
{
BackgroundWorker AppWorker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
AppWorker.WorkerSupportsCancellation = true;
AppWorker.DoWork += AppWorker_DoWork;
AppWorker.RunWorkerCompleted += AppWorker_RunWorkerCompleted;
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
lstTest.Items.Add("Processing data...");
AppWorker.RunWorkerAsync();
}
public void AppWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
SetXmlData xml = new SetXmlData();
xml.ProgressUpdate += (s, evt) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : " + evt.myData); //how to retrieve the myData property from evt ?
}));
};
xml.FlushData();
}
public void AppWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (!(e.Cancelled))
{
lstTest.Items.Add("Done");
}
else
{
MessageBox.Show("Cancelled");
}
}
}
}
SetXmlData.cs
namespace AppMain
{
public class SetXmlData
{
public event EventHandler ProgressUpdate;
//update method
public void update(object input)
{
if (ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs { myData = (string)input });
}
//calculation method
public void FlushData()
{
MessageBox.Show("this is a test !");
update("test");
}
}
public class YourEventArgs : EventArgs
{
public string myData { get; set; }
}
}
感谢您的帮助。
您可以简单地从 FlushData()
方法中调用 ProgressUpdate
事件。
只需调用:
If (ProgressUpdate !=null )
{
ProgressUpdate(this,new YourEventArgs())
}
this
是 event
的源实例。
您可以通过从 EventArgs
class 继承来创建 YourEventArgs。
public class YourEventArgs : EventArgs
{
//Put any property that you want to pass back to UI here.
}
当 event
在 UI 中被引发时:
RaiseEvent.ProgressUpdate += (s, e) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : ");
//Add items to your UI control here...
}));
};
e 将是 YourEventArgs
类型。
附带说明一下,您永远不应该接触来自不同线程的 UI 线程(例如示例中的后台工作线程)。由于您的 event-handler
已经执行了 Dispatcher.BeginInvoke
,所以这是安全的。
此外,您的 ProgressUpdate
事件应该在您的 class SetXmlData 中。
尝试获取;设置;示例:
表格 1:
public partial class Form1 : Form
{
static public string gettext { get; set; }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Class1.send(); //call to class function
textBox1.Text = gettext; //items.add(gettext)
}
}
第 1 类:
class Class1
{
static public void send()
{
Form1.gettext = "Marko"; //Set gettext to string "Marko"
}
}
我实际上正在学习(艰难地)c# 并且一直在为一个问题而奋斗:
我正在使用 WPF (dotNet 4.0) 编写我的第一个 c# 应用程序。当我单击一个按钮时,会使用一个 BackgroundWorker 线程并从外部 class 调用一个方法,这样我的 UI 就不会冻结 -> 我的方法 运行 如预期的那样。
然后我尝试从那些外部 class 更新 ListView 控件以获得某种进展(文本),但我悲惨地失败了。
我知道我需要使用委托和调度程序来更新我的控件。
我尝试使用此处提供的解决方案 How to update UI from another thread running in another class。 (由于我的代表率低,我无法对此发表评论)并且我错过了拼图的某些部分。
YourEventArgs(status) 指的是什么?我只是不知道触发事件并将内容传回我的 UI 的方法,而我的方法是 运行 在 BGW 中。
到目前为止我有这段代码(更新自答案):
namespace AppMain
{
public partial class MainWindow
{
BackgroundWorker AppWorker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
AppWorker.WorkerSupportsCancellation = true;
AppWorker.DoWork += AppWorker_DoWork;
AppWorker.RunWorkerCompleted += AppWorker_RunWorkerCompleted;
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
lstTest.Items.Add("Processing data...");
AppWorker.RunWorkerAsync();
}
public void AppWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
SetXmlData xml = new SetXmlData();
xml.ProgressUpdate += (s, evt) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : " + evt.myData); //how to retrieve the myData property from evt ?
}));
};
xml.FlushData();
}
public void AppWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (!(e.Cancelled))
{
lstTest.Items.Add("Done");
}
else
{
MessageBox.Show("Cancelled");
}
}
}
}
SetXmlData.cs
namespace AppMain
{
public class SetXmlData
{
public event EventHandler ProgressUpdate;
//update method
public void update(object input)
{
if (ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs { myData = (string)input });
}
//calculation method
public void FlushData()
{
MessageBox.Show("this is a test !");
update("test");
}
}
public class YourEventArgs : EventArgs
{
public string myData { get; set; }
}
}
感谢您的帮助。
您可以简单地从 FlushData()
方法中调用 ProgressUpdate
事件。
只需调用:
If (ProgressUpdate !=null )
{
ProgressUpdate(this,new YourEventArgs())
}
this
是 event
的源实例。
您可以通过从 EventArgs
class 继承来创建 YourEventArgs。
public class YourEventArgs : EventArgs
{
//Put any property that you want to pass back to UI here.
}
当 event
在 UI 中被引发时:
RaiseEvent.ProgressUpdate += (s, e) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : ");
//Add items to your UI control here...
}));
};
e 将是 YourEventArgs
类型。
附带说明一下,您永远不应该接触来自不同线程的 UI 线程(例如示例中的后台工作线程)。由于您的 event-handler
已经执行了 Dispatcher.BeginInvoke
,所以这是安全的。
此外,您的 ProgressUpdate
事件应该在您的 class SetXmlData 中。
尝试获取;设置;示例:
表格 1:
public partial class Form1 : Form
{
static public string gettext { get; set; }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Class1.send(); //call to class function
textBox1.Text = gettext; //items.add(gettext)
}
}
第 1 类:
class Class1
{
static public void send()
{
Form1.gettext = "Marko"; //Set gettext to string "Marko"
}
}