后台工作线程调用方法或其他东西



我有一个运行良好的方法/过程,但是它需要很长时间才能完成它的工作,所以我想将其移动到后台工作者中,以便人们仍然可以使用该应用程序。

这是代码。(我尽可能多地削减)

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();
        }
    }

那么,如何让我的后台辅助角色运行我创建的发现方法呢?

您需要

DoWork事件处理程序中完成工作。

我不知道

你是否需要一个完整的单独类。我更喜欢根据需要即时创建它们。我认为你会把自己硬塞进去,你会在多个地方使用你的类,然后决定在某些情况下Workers_Completed做其他事情,或者在某些情况下发生错误时做一些不同的事情,而一个类最终可能会成为一个纠结的痛苦。不过这只是我的意见。

此外,您必须非常小心地从后台工作者接触 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);

SLaks 的答案是正确的,但你显然不明白这意味着什么。我建议把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 属性的值。我还包括一种检测取消的简单方法;我会将进度报告留给您实施。

相关内容

最新更新