我有一个方法/程序运行良好,但是它需要很长时间才能完成它,所以我想将它移动到后台工作程序中,这样人们仍然可以使用该应用程序。
这是代码。 (我尽可能地减少了)
public partial class NetworkInformation : UserControl, INotifyPropertyChanged
{
public NetworkInformation()
{
InitializeComponent();
Discovery();
}
public void Discovery()
{
GetIcon Icon = new GetIcon();
BitmapImage IconOfComputer = null;
List<DiscoveredComputer> NetworkedComputers = new List<DiscoveredComputer>();
DirectoryEntry Discover = new DirectoryEntry("WinNT://Workgroup");
BitmapImage On = Icon.LoadIcon(@"/Images/Icons/ComputerOn.ico");
BitmapImage Off = Icon.LoadIcon(@"/Images/Icons/ComputerOff.ico");
foreach (DirectoryEntry Node in Discover.Children)
{
try
{
if (Node.Properties.Count > 0)
{
IconOfComputer = On;
}
}
catch
{
IconOfComputer = Off;
}
if (Node.Name != "Schema") { NetworkedComputers.Add(new DiscoveredComputer { Image = IconOfComputer, ComputerName = Node.Name, MyToolTip = "Node Type = " + Node.SchemaEntry.Name }); }
}
ListView_LocalComputers.ItemsSource = NetworkedComputers;
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public class DiscoveredComputer : INotifyPropertyChanged
{
private string _ComputerName;
public string ComputerName
{
get { return _ComputerName; }
set
{
_ComputerName = value;
this.NotifyPropertyChanged("ComputerName");
}
}
private BitmapImage _Image;
public BitmapImage Image {
get { return _Image; }
set
{
_Image = value;
this.NotifyPropertyChanged("Image");
}
}
private String _MyToolTip;
public String MyToolTip
{
get { return _MyToolTip; }
set
{
_MyToolTip = value;
this.NotifyPropertyChanged("ToolTip");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
public class GetIcon
{
public BitmapImage IconStorage { get; set; }
public BitmapImage LoadIcon(String IconPath)
{
BitmapImage GeneratedIcon = new BitmapImage();
GeneratedIcon.BeginInit();
GeneratedIcon.UriSource = new Uri("pack://application:,,," + IconPath, UriKind.RelativeOrAbsolute);
GeneratedIcon.EndInit();
IconStorage = GeneratedIcon;
return GeneratedIcon;
}
}
}
这一切都很棒,不知怎的......
以下是我为后台工作人员开发的代码
public partial class MyBackgroundWorker : UserControl
{
WorkerData BGW;
public MyBackgroundWorker()
{
InitializeComponent();
BGW = new WorkerData();
#region Workers Events
BGW.ThisWorker.DoWork += new DoWorkEventHandler(Workers_DoWork);
BGW.ThisWorker.ProgressChanged += new ProgressChangedEventHandler(Workers_Progress);
BGW.ThisWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(Workers_Completed);
BGW.ThisWorker.WorkerReportsProgress = true;
BGW.ThisWorker.WorkerSupportsCancellation = true;
#endregion
}
public void RibbonButton_EventClickStart(object sender, RoutedEventArgs e)
{
BGW.ThisWorker.RunWorkerAsync();
}
public void UserForm_Loaded(object sender, RoutedEventArgs e)
{
}
public void RibbonButton_EventClick(object sender, RoutedEventArgs e)
{
BGW.ThisWorker.CancelAsync();
}
public void Workers_DoWork(object sender, DoWorkEventArgs e)
{
}
public void Workers_Progress(object sender, ProgressChangedEventArgs e)
{
BGW.ThisWorkersProgress = e.ProgressPercentage;
}
public void Workers_Completed(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) { BGW.ThisWorkersResult = "Cancelled By User"; }
else if (e.Error != null) { BGW.ThisWorkersResult = "Error Encountered: " + e.Error.Message; }
else
{
BGW.ThisWorkersResult = "Task Completed Successfully";
BGW.WorkersReturnObject = e.Result;
}
}
}
public class WorkerData
{
public BackgroundWorker ThisWorker { get; set; }
public int ThisWorkersProgress { get; set; }
public string ThisWorkersResult { get; set; }
public object WorkersReturnObject { get; set; }
public object ThisWorkersJob { get; set; }
public WorkerData()
{
ThisWorker = new BackgroundWorker();
}
}
那么如何让我的后台工作者运行我创建的Discovery方法呢?
答案 0 :(得分:3)
您需要在DoWork
事件处理程序中完成工作。
答案 1 :(得分:2)
我不知道你是否需要一个完全独立的课程。我喜欢在飞行中创建这些,因为我需要它们。我认为你会让自己变得愚蠢,你会在多个地方使用你的课程,然后在某些情况下决定你想在Workers_Completed
做其他事情,或者在某些情况下发生错误时做一些不同的事情,并且一个班级可能最终成为一个纠结的痛苦。这只是我的观点。
此外,您必须非常小心从BackgroundWorker中触摸UI线程。在下面的示例中,我将您的节点计数传递给DoWork
事件,而不是直接触摸UI组件。我也将列表传递给RunWorkerCompleted
事件,以便在尝试将列表附加到ListView时返回主线程。
var bw = new BackgroundWorker();
bw.DoWork += (s, e) =>
{
var nodePropertiesCount = (int)e.Argument;
// the guts of `Discovery` go in here
e.Result = NetworkedComputers;
};
bw.RunWorkerCompleted += (s, e) =>
{
if (e.Error != null)
{
// Task Completed Successfully
ListView_LocalComputers = (List<DiscoveredComputer>)e.Result;
}
else
{
// Error Encountered
}
};
bw.RunWorkerAsync(Node.Properties.Count);
答案 2 :(得分:1)
SLaks answer是正确的,但你显然不明白这意味着什么。我建议采用Discover()
的胆量并将它们放入Workers_DoWork()
方法中,如下所示:
public void Workers_DoWork(object sender, DoWorkEventArgs e)
{
var backgroundWorker = sender as BackgroundWorker;
GetIcon Icon = new GetIcon();
BitmapImage IconOfComputer = null;
List<DiscoveredComputer> NetworkedComputers = new List<DiscoveredComputer>();
DirectoryEntry Discover = new DirectoryEntry("WinNT://Workgroup");
BitmapImage On = Icon.LoadIcon(@"/Images/Icons/ComputerOn.ico");
BitmapImage Off = Icon.LoadIcon(@"/Images/Icons/ComputerOff.ico");
while (!backgroundWorker.CancellationPending)
{
foreach (DirectoryEntry Node in Discover.Children)
{
try
{
if (Node.Properties.Count > 0)
{
IconOfComputer = On;
}
}
catch
{
IconOfComputer = Off;
}
if (Node.Name != "Schema") { NetworkedComputers.Add(new DiscoveredComputer { Image = IconOfComputer, ComputerName = Node.Name, MyToolTip = "Node Type = " + Node.SchemaEntry.Name }); }
}
break;
}
if(backgroundWorker.CancellationPending)
{
e.Cancel = true;
}
else
{
e.Result = NetworkedComputers;
}
}
然后像这样修改你的Workers_Completed()
:
public void Workers_Completed(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled) { BGW.ThisWorkersResult = "Cancelled By User"; }
else if (e.Error != null) { BGW.ThisWorkersResult = "Error Encountered: " + e.Error.Message; }
else
{
BGW.ThisWorkersResult = "Task Completed Successfully";
//BGW.WorkersReturnObject = e.Result;
//background worker can't touch UI components
ListView_LocalComputers.ItemsSource = e.Result as List<DiscoveredComputer>;
}
}
我建议这些更改或类似的东西,因为后台工作程序无法修改/访问UI组件(如ListView),因此它必须传回用于ListView视图的值Result
属性。我还提供了一种检测取消的简单方法;我会将进度报告留给您实施。