c# - Using a Stopwatch and DataBinding on a WPF Window that is already being updated using IProgress -


in main() wpf program run time consuming method asynchronously. when method running, fire secondary window contains progressbar, update using iprogress.

following example of setup.

main program:

public partial class mainwindow : window {     private progressbarwindow pbwwindow = null;      public mainwindow()     {         initializecomponent();     }      private void runmethodasync(iprogress<int> progress)     {         dispatcher.invoke(() =>         {             pbwwindow = new progressbarwindow("processing...");             pbwwindow.owner = this;             pbwwindow.show();         });          timeconsumingmethod(progress);     }      private void timeconsumingmethod(iprogress<int> progress)     {         (int = 1; <= 100; i++)         {             // thread.sleep() represents actual time consuming work being done.             thread.sleep(100);             progress.report(i);         }     }      private async void btnrun_click(object sender, routedeventargs e)     {         iprogress<int> progress;          progress = new progress<int>(i => pbwwindow.setprogressupdate(i));         await task.run(() => runmethodasync(progress));     } } 

my progressbarwindow contains progress bar looks this:

public partial class progressbarwindow : window {     stopwatch stopwatch = new stopwatch();     backgroundworker worker = new backgroundworker();     public string elapsedtimestring { get; set; }      public progressbarwindow(string infotext)     {         initializecomponent();         settimer();     }      private void window_loaded(object sender, routedeventargs e)     {         starttimer();     }      private void settimer()     {         worker.workerreportsprogress = true;         worker.workersupportscancellation = true;          worker.dowork += (s, e) =>         {             while (!worker.cancellationpending)             {                 worker.reportprogress(0, stopwatch.elapsed);                 thread.sleep(1000);             }         };          worker.progresschanged += (s, e) =>         {             timespan elapsedtime = (timespan)e.userstate;             elapsedtimestring = string.format("{0}:{1}:{2}", elapsedtime.minutes, elapsedtime.seconds, elapsedtime.milliseconds);         };     }      private void starttimer()     {         stopwatch.start();         worker.runworkerasync();     }      private void stoptimer()     {         stopwatch.stop();         worker.cancelasync();     }      public void setprogressupdate(int progress)     {         pbload.value = progress;         if (progress >= 100)         {             stoptimer();             close();         }     } } 

i borrowed stopwatch logic this answer. then, on progressbarwindow have textblock i've used binding follows, answer above says.

<textblock name="tbelapsedtime" text="{binding elapsedtimestring}"/> 

now when run program, method executes, , progress bar updates fine. however, textblock that's supposed update elapsed time not updated.

to verify timer's running fine, updated textblock value directly follows instead of binding , worked expected , displayed elapsed time:

worker.progresschanged += (s, e) =>         {             timespan elapsedtime = (timespan)e.userstate;             elapsedtimestring = string.format("{0}:{1}:{2}", elapsedtime.minutes, elapsedtime.seconds, elapsedtime.milliseconds);             tbelapsedtime.text = elapsedtimestring;         }; 

so i'm guessing problem binding , possibly using backgroundworker on windows that's being run asynchronously? how fix use databinding?

as mentioned ginger ninja, have implement inotifypropertychanged , use relativesource={relativesource self} (as additional setting binding):

public partial class mainwindow : window, inotifypropertychanged {     public event propertychangedeventhandler propertychanged;      private string _elapsedtimestring;     public string elapsedtimestring     {         { return _elapsedtimestring; }         set         {             if (_elapsedtimestring != value)             {                 _elapsedtimestring = value;                 propertychanged?.invoke(this, new propertychangedeventargs("elapsedtimestring"));             }         }     }      // .... } 

and xaml:

<textblock name="tbelapsedtime" text="{binding elapsedtimestring, relativesource={relativesource self}}"/> 

data binding used in combination mvvm. imho prefered way solve problem... if want use mvvm, have implement view model contains logic , implements inotifypropertychanged. can bind properties view model view. ensures nice separation between (gui related) logic , view.


Comments

Popular posts from this blog

javascript - Create a stacked percentage column -

Optimising Firebase database by automatically overwriting data -

javascript - Angular UI-Grid customTemplate directive causing rows to load slowly/? -