2016-11-05 4 views
2

Я не эксперт в области C#, но то, что я пытаюсь сделать, это обновить прогресс в рабочем документе. Я использую следующий код:C# ProgressBar Databindings в backgroundworker

progressBar1.DataBindings.Add("Value", _dm, "Progress", true, 
           DataSourceUpdateMode.OnPropertyChanged); 

Это работает, когда выполняется без фонового работника в потоке графического интерфейса пользователя. Свойство «Прогресс» - это свойство, которое обновляет (используя INotifyPropertyChanged) из хода выполнения другого фонового работника (где у меня нет доступа).

Как я могу заставить его работать так, чтобы он обновлялся с использованием рабочего стола вместо того, чтобы помещать его в поток графического интерфейса?

Мой код (упрощенно):

class DownloadManager : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged; 

    private double _progressValue; 

    public double Progress 
    { 
     get { return _progressValue; } 
     private set 
     { 
      if (!value.Equals(_progressValue)) 
      { 
       _progressValue = value; 
       PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Progress")); 
      } 
     } 
    } 

    public void Download() 
    { 
     var downloader = new Downloader(); 

     downloader.DownloadProgressChanged += (sender, e) 
       => Progress = e.ProgressPercentage; 

     downloader.Execute(); 
    } 
} 

public partial class MainForm 
{ 
    private readonly DownloadManager _dm; 
    public MainForm() 
    { 
     InitializeComponent(); 
     _dm = new DownloadManager(); 
    } 

    private void btnDownload_Click(object sender, EventArgs e) 
    { 
      //TRIED HERE ... 
      progressBar1.DataBindings.Add("Value", _dm, "Progress", true, 
              DataSourceUpdateMode.OnPropertyChanged); 
      bwDownload.RunWorkerAsync(); 
     } 
    } 

    private void bwDownload_DoWork(object sender, DoWorkEventArgs e) 
    { 
     //AND TRIED HERE 
     progressBar1.DataBindings.Add("Value", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged); 

     //THIS AINT WORKING EITHER 
     if (progressBar1.InvokeRequired) { 
      progressBar1.Invoke(new MethodInvoker(() 
       => progressBar1.DataBindings.Add("Value", _dm, "Progress", true, 
             DataSourceUpdateMode.OnPropertyChanged))); 
    } 

     _dm.Download(); 
    } 
} 

ответ

2

привязок данных должны быть созданы в конструкторе, как вам нужно, чтобы создать привязку только один раз, а не каждый раз, когда это необходимо:

public MainForm() 
{ 
    InitializeComponent(); 
    _dm = new DownloadManager(); 
    progressBar1.DataBindings.Add("Value", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged); 
} 

Ваш код не работает, потому что вы пытаетесь для обновления пользовательского интерфейса из потока, отличного от ui. Вам нужно нужно обернуть код в Invoke() вызова, например, с помощью прокси-свойства в Форме:

public partial class MainForm 
{ 
    private double _progress; 
    public double Progress 
    { 
     get { return _progress; } 
     set 
     { 
      _progress = value; 

      // If not in the UI thread -> wrap the update in an Invoke() call: 
      if (this.InvokeRequired) 
      { 
       this.Invoke(new Action(() => progressBar1.Value = (int) _progress), new object[] { }); 
       return; 
      } 

      // Else update directly 
      progressBar1.Value = (int) value; 
     } 
    } 

    private readonly DownloadManager _dm; 
    public MainForm() 
    { 
     InitializeComponent(); 
     _dm = new DownloadManager(); 

     // Bind _db.Progress <-> this.Progress 
     DataBindings.Add("Progress", _dm, "Progress", true, DataSourceUpdateMode.OnPropertyChanged); 
    } 
0

элементы графического интерфейса пользователя необходимо обновить в потоке пользовательского интерфейса. Для обновления свойств элементов управления необходимо использовать Control.Invoke. Mora об этой проблеме: Data Binding on multi thread application?

+0

не работает либо .. я забыл добавить, что мой упрощенный код – JC97