How to open any view in BackgroundWorker? - wpf

In my desktop application i want to open view in BackgroundWorker to show reminder.
but when i try to open view it gives me the following error.
"The calling thread must be STA, because many UI components require this."
and stackTrace is
at System.Windows.Input.InputManager..ctor()
at System.Windows.Input.InputManager.GetCurrentInputManagerImpl()
at System.Windows.Input.KeyboardNavigation..ctor()
at System.Windows.FrameworkElement.FrameworkServices..ctor()
at System.Windows.FrameworkElement.EnsureFrameworkServices()
at System.Windows.FrameworkElement..ctor()
at System.Windows.Controls.Control..ctor()
at System.Windows.Window..ctor()
at MahApps.Metro.Controls.MetroWindow..ctor()
can anyone have solution?

you can do this in this manner:
private BackgroundWorker _BgWorker;
public Window1()
{
InitializeComponent();
_BgWorker = new BackgroundWorker();
_BgWorker.DoWork += new DoWorkEventHandler(bgw_DoWork);
_BgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
}
void bgw_DoWork(object sender, DoWorkEventArgs e)
{
///your code to get the data from database...
}
void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//you code to open a view
}
Use this in the Runworker completed
Thread Messagethread = new Thread(
new ThreadStart(delegate()
{
DispatcherOperation DispacherOP = frmMassenger.Dispatcher
.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate()
{
frmMassenger.Show();
}
));
} ));
Messagethread.Start();
later you join the Thread with main thread using:
Thread.join(userthread);
Hope This will help you.

Related

Best way to continuously monitor a MSMQ queue in WPF

I need my WPF exe to start monitoring a queue as soon as it starts up, and then respond to messages as they come in.
The way I have it now is:
public partial class App
{
readonly BackgroundWorker _worker = new BackgroundWorker();
protected override void OnStartup(StartupEventArgs e)
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerAsync();
}
static void worker_DoWork(object sender, DoWorkEventArgs e)
{
//do work
}
Obviously, this is pretty pathetic IMO.
Also, I don't like the approach of using while(true), inside the thread to keep it running indefinitely..
It's enough to read the messages from queue not permanently but periodically.
The common approach for this is using timer. For example, System.Threading.Timer.
public partial class App : Application
{
private System.Threading.Timer _msmqReadTimer;
public App()
{
_msmqReadTimer = new System.Threading.Timer(MsmqReadTimerTick);
_msmqReadTimer.Change(0, 1000); // call MsmqReadTimerTick immediatelly and each 1000 ms
}
private void MsmqReadTimerTick(object state)
{
// do work
// if you want to update some UI components after work, you should post this to UI thread dispatcher:
this.Dispatcher.Invoke(()=>
{
// logic for updating UI should be here
},
System.Windows.Threading.DispatcherPriority.Background);
}
}

WPF Backgroundwork er call method on DoWork event

I have a BackgroundWorker on my WPF UserControl.
private readonly BackgroundWorker worker = new BackgroundWorker();
public ucCustomer()
{
InitializeComponent();
worker.DoWork += worker_DoWork;
worker.RunWorkerCompleted += worker_RunWorkerCompleted;
}
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
System.Threading.Thread.Sleep(10000);
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//update ui once worker complete his work
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
worker.RunWorkerAsync();
}
Above code is work, the UI is response when the task is working, but if i change the worker_DoWork() to
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() => {
gridDataBind(); //A long data-mining task,using Dispatcher.Invoke() to access UI.
}));
}
private void gridDataBind()
{
SnEntities sn = new SnEntities();
var customers = from c in sn.Customer select c;
dgCustomer.ItemsSource = customers.ToList();
}
The UI is freeze until the task is end.
Is it any solution?
Thanks you.
Try setting the ItemsSource like below code:
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
// run all background tasks here
e.Result = gridDataBind(); //A long data-mining task.
}
private IList<Customer> gridDataBind()
{
SnEntities sn = new SnEntities();
var customers = from c in sn.Customer select c;
return customers.ToList();
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
var customers = e.Result as IList<Customer>;
ObservableCollection<Customer> gridItemsSource = new ObservableCollection<Customer>();
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() =>
{
dgCustomer.ItemsSource = gridItemsSource;
}));
foreach(var customer in customers)
{
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
new Action(() =>
{
gridItemsSource.Add(customer);
}));
}
}
Store your data in e.result at worker_DoWork and update UI at the worker_RunWorkerCompleted.
in that case UI will be free when data will coming from database.
Try this, it should help you
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() => gridDataBind();));

Why a second UI thread freezes the first one?

I've got an application with two UI threads and one background worker. Everything works fine except that handling ProgressChanged in the second simulation UI thread blocks the first one. Why it happens? How can I workaround this (I want the second one be blocked instead of the main UI thread)?
Part of MainWindow class:
private SimulationWindow simulationWindow;
public MainWindow()
{
InitializeComponent();
Thread thread = new Thread(() =>
{
simulationWindow = new SimulationWindow();
simulationWindow.Show();
simulationWindow.Closed += (sender2, e2) =>
simulationWindow.Dispatcher.InvokeShutdown();
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
private void start_Click(object sender, RoutedEventArgs e)
{
simulationWindow.Start();
}
Part of SimulationWindow class:
private BackgroundWorker bw;
public SimulationWindow()
{
InitializeComponent();
bw = new BackgroundWorker() { WorkerReportsProgress = true, WorkerSupportsCancellation = true };
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//some complex computation will go here
//Thread.Sleep(10000); <- both windows responsive, OK
bw.ReportProgress(0);
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
//some complex rendering will go here
Thread.Sleep(10000); // this blocks main UI thread, why?
}
public void Start()
{
bw.RunWorkerAsync();
}
private void doSth_Click(object sender, RoutedEventArgs e)
{
Thread.Sleep(10000); // freezes simulationWindow, which was understandable
}
You call simulationWindow.Start() on the main UI thread. This means the BW is started on that thread, which means it captures the SynchronizationContext of the main UI thread and so also raises ProgressChanged on that thread.
You need to marshal the call to bw.RunWorkerAsync() on to your second thread. You can do this in SimulationWindow.Start() by calling this.Dispatcher.Invoke and passing bw.RunWorkerAsync() as the delegate. It should then run on your second window thread and the events will be raised on that thread.

WPF & Multi-threading questions

I'm working on building a multi-threaded UI. I would like long processes to be handled by the BackgroundWorker class, and have a small timer on the UI to keep track of how long the process is taking. It's my first time building such a UI, so I'm reading up on related resources on the web. My test code is thus:
private BackgroundWorker worker;
private Stopwatch swatch = new Stopwatch();
private delegate void simpleDelegate();
System.Timers.Timer timer = new System.Timers.Timer(1000);
string lblHelpPrevText = "";
private void btnStart_Click(object sender, RoutedEventArgs e)
{
try
{
worker = new BackgroundWorker(); //Create new background worker thread
worker.DoWork += new DoWorkEventHandler(BG_test1);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BG_test1end);
worker.RunWorkerAsync();
simpleDelegate del = new simpleDelegate(clockTicker);
AsyncCallback callBack = new AsyncCallback(clockEnd);
IAsyncResult ar = del.BeginInvoke(callBack, null);
lblHelpText.Text = "Processing...";
}
finally
{
worker.Dispose(); //clear resources
}
}
private void clockTicker()
{
//Grab Text
simpleDelegate delLblHelpText = delegate()
{ lblHelpPrevText = this.lblHelpText.Text; };
this.Dispatcher.BeginInvoke(DispatcherPriority.Send, delLblHelpText);
//Start clock
timer.Elapsed += new ElapsedEventHandler(clockTick);
timer.Enabled = true;
swatch.Start();
}
private void clockTick(object sender, ElapsedEventArgs e)
{
simpleDelegate delUpdateHelpTxt = delegate()
{ this.lblHelpText.Text = String.Format("({0:00}:{1:00}) {2}", swatch.Elapsed.Minutes, swatch.Elapsed.Seconds, lblHelpPrevText); };
this.Dispatcher.BeginInvoke(DispatcherPriority.Send, delUpdateHelpTxt);
}
private void BG_test1(object sender, DoWorkEventArgs e)
{
//this.lblHelpText.Text = "Processing for 10 seconds...";
Thread.Sleep(15000);
}
private void BG_test1end(object sender, RunWorkerCompletedEventArgs e)
{
this.lblHelpText.Text = "Process done.";
this.timer.Enabled = false;
this.swatch.Stop();
this.swatch.Reset();
}
static void clockEnd(IAsyncResult ar)
{
simpleDelegate X = (simpleDelegate)((AsyncResult)ar).AsyncDelegate;
X.EndInvoke(ar);
}
The idea is when the button is clicked, we take the status text from a Label (e.g. "Processing...") then append the time onto it every second. I could not access the UI elements from the Timer class as it's on a different thread, so I had to use delegates to get and set the text.
It works, but is there a better way to handle this? The code seems much for such a basic operation. I'm also not fully understanding the EndInvoke bit at the bottom. I obtained the snippet of code from this thread Should One Always Call EndInvoke a Delegate inside AsyncCallback?
I understand the idea of EndInvoke is to receive the result of BeginInvoke. But is this the correct way to use it in this situation? I'm simply worried about any resource leaks but when debugging the callback appears to execute before my timer starts working.
Don't use a separate timer to read the progress of your BackgroundWorker and update the UI. Instead, make the BackgroundWorker itself "publish" its progress to the UI directly or indirectly.
This can be done pretty much anyway you want to, but there's a built-in provision exactly for this case: the BackgroundWorker.ProgressChanged event.
private void BG_test1(object sender, DoWorkEventArgs e)
{
for(var i = 0; i < 15; ++i) {
Thread.Sleep(1000);
// you will need to get a ref to `worker`
// simplest would be to make it a field in your class
worker.ReportProgress(100 / 15 * (i + 1));
}
}
This way you can simply attach your own handler to ProgressChanged and update the UI using BeginInvoke from there. The timer and everything related to it can (and should) go.
You can use timer to update UI. It is normal practice. Just instead of System.Timer.Timer I suggest use System.Windows.Threading.DispatcherTimer. The DispatcherTimer runs on the same thread as the Dispatcher. Also, instead of BackgroundWorker you can use ThreadPool.
Here is my sample:
object syncObj = new object();
Stopwatch swatch = new Stopwatch();
DispatcherTimer updateTimer; // Assume timer was initialized in constructor.
void btnStart_Click(object sender, RoutedEventArgs e) {
lock (syncObj) {
ThreadPool.QueueUserWorkItem(MyAsyncRoutine);
swatch.Start();
updateTimer.Start();
}
}
void updateTimer_Tick(object sender, EventArgs e) {
// We can access UI elements from this place.
lblHelpText.Text = String.Format("({0:00}:{1:00}) Processing...", swatch.Elapsed.Minutes, swatch.Elapsed.Seconds);
}
void MyAsyncRoutine(object state) {
Thread.Sleep(5000);
lock (syncObj)
Dispatcher.Invoke(new Action(() => {
swatch.Stop();
updateTimer.Stop();
lblHelpText.Text = "Process done.";
}), null);
}
private void button1_Click(object sender, EventArgs e)
{
string strFullFilePath = #"D:\Print.pdf";
ProcessStartInfo ps = new ProcessStartInfo();
ps.UseShellExecute = true;
ps.Verb = "print";
ps.CreateNoWindow = true;
ps.WindowStyle = ProcessWindowStyle.Hidden;
ps.FileName = strFullFilePath;
Process.Start(ps);
Process proc = Process.Start(ps);
KillthisProcess("AcroRd32");
}
public void KillthisProcess(string name)
{
foreach (Process prntProcess in Process.GetProcesses())
{
if (prntProcess.ProcessName.StartsWith(name))
{
prntProcess.WaitForExit(10000);
prntProcess.Kill();
}
}
}

Threading problem in WPF

I'm getting this Exception
System.InvalidOperationException was
unhandled by user code Message="The
calling thread cannot access this
object because a different thread owns
it."
whenever I run the following code
public partial class MainScreen : Window
{
Timer trm;
public MainScreen()
{
InitializeComponent();
trm = new Timer(1000);
trm.AutoReset = true;
trm.Start();
trm.Elapsed += new ElapsedEventHandler(trm_Elapsed);
}
void trm_Elapsed(object sender, ElapsedEventArgs e)
{
lblTime.Content = System.DateTime.Now;
}
}
guys any solution... I badly wann come out of it :(
Use DispatcherTimer instead:
public partial class MainScreen : Window{
DispatcherTimer tmr;
public MainScreen() {
InitializeComponent();
tmr = new DispatcherTimer();
tmr.Tick += new EventHandler(tmr_Tick);
tmr.Start();
}
void tmr_Tick(object sender, EventArgs e) {
lblTime.Content = System.DateTime.Now;
}
}
Any time you modify Windows controls you must do so on the UI thread (the one that created the controls).
See this question for lots of details.
To be short, you should use Dispatcher.Invoke method to update UI elements.

Resources