背景工人呼叫方法或某事

时间:2014-01-03 14:00:40

标签: c# wpf backgroundworker

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

这是代码。 (我尽可能地减少了)

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方法呢?

3 个答案:

答案 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属性。我还提供了一种检测取消的简单方法;我会将进度报告留给您实施。