Reputation: 152
I have a status bar on a window that I want to update with a string while a background process is running.
Specifically the user presses a button, and data is read from a file. As the file is being read, backend db calls are made to populate data objects. This is done for all lines in the file. This can take a little bit of time. This is all done in a background worker.
What I want to do is provide the user with some feel that something is happening. I would like to present the user with the name of the object that was just read in on a status line. I see BackgroundWorker provides an interger update value, but how do I do a string so that I can display it?
Upvotes: 2
Views: 810
Reputation: 1585
This is a common problem people face in WPF. I imagine you are trying to update a label from a BackgroundWorker and you are being plagued by "a different thread owns it" errors. You will probably find answers telling you to use a dispatcher to update your label. DON'T DO IT! It's unreliable and often doesn't update under heavy workloads. You should use proper binding techniques in your instance.
Hopefully this example (though not necessarily the most refactored, nor quickest to implement) can get you started on the right path, by explaining some core fundamentals or WPF.
Create an observable class that implements INotifyPropertyChanged
. This is your Model. Its basically the shell of how your data will be stored (in your instance a status).
using System.ComponentModel;
public class Status_Update : INotifyPropertyChanged
{
//private property that stores value
private string status;
//public property the gets & sets value
public string Status
{
get {return status;}
set
{
if(status != value)
{
status = value;
NotifyPropertyChanged("Status");
}
}
}
//Logic to notify that property values have changed.
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
Now lets move to your Control or Window's code behind constructor.
//Create a Status_Update object in your control.
public Status_Update My_Status {get;set;}
public My_Control_or_Window()
{
//Initialize the Status_Update object
MyStatus = new Status_Update(){Status=""};
InitializeComponent();
//Set the controls DataContext to itself in the constructor
DataContext=this;
}
Now in your frontend's XAML you simply bind to your control's MyStatus.Status
property and it's ready for live updates from any calling thread.
<Label Content={Binding MyStatus.Status, UpdateSourceTrigger=PropertyChanged}/>
To update simply set the value of MyStatus.Status
from your BackgroundWorker.
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
MyStatus.Status = "Updating the first item";
Some_Task();
MyStatus.Status = "Updating the next item";
Some_Task();
}
I want to note that this example isn't the best example of MVVM, nor is it the best code structure for what you are trying to do, but it should help give you a better understanding of how binding works in WPF and how you can update things like a status label much easier with it. It takes a little more work on the front end, but saves so much time on the back end.
Best of luck.
Upvotes: 3