PDA

Click to See Complete Forum and Search --> : [RESOLVED] WPF version of DoEvents


techgnome
May 20th, 2009, 03:48 PM
Working on my first "real" WPF app ... it's a utility that will help us (me) create our deployment structure faster by automating a bunch of tedious tasks that are prone to errors. It has to create a directory structure, then copy a bunch of files around. As part of this, I'd like it to report its progress as it creates the folders and copies the files. So, as it goes through each step, I have it displying the current status to a ListView (I realyl should change it to a listbox, as the reason for the listview is no longer valid). I've got it working for the most part.... except for one thing. After the user (that's me) clicks the button, it "hangs" for a few seconds while the process runs. Since speed isn't of the essence here, normally in a windows app, after posting the status to the listview, I'd issue a DoEvents to give the system a chance to refresh the screen, and I'd go on my merry way. However, DoEvents doesn't exist in the WPF realm... and there doesn't appear to be a Refresh method on the listview or form.... so.....

What do I need to do to get the display to update? Do I need to sacrifice an animal to the WPF gods in the MS Temple in Redmond? Or is there something I'm missing? Eventually, I'd also like to add a progress bar, so it would be really nice if the display didn't lock itself up.

-tg

dee-u
May 20th, 2009, 04:23 PM
Found this (http://www.cnblogs.com/sheva/archive/2006/08/24/485790.html) on google.

DeanMc
May 20th, 2009, 04:30 PM
My overall feeling on DoEvents() is that is a very naughty boy! I would probably look more into invalidating the control and causing it to repaint midway between your logic.

But for the moment a sacrifice has been made and this is what I have gotten back: http://blogs.microsoft.co.il/blogs/tamir/archive/2007/08/21/How-to-DoEvents-in-WPF_3F00_.aspx

The code is C# but it is pretty simple to decipher and also not that long, it essentially shows you how to make a DoEvents() object to use in secret.

DeanMc
May 20th, 2009, 04:34 PM
Also, I know this is crazy but what happens if you add a reference to system.windows.forms.dll. You could then use DoEvents() via System.Windows.Forms.Application.DoEvents() or at least it SHOULD work!

techgnome
May 20th, 2009, 04:42 PM
Yuck! That's the kind of stuff I was trying to avoid.

I think I found my answer though.... I'll have to play with it later.... I may simply have to spin the process off in its own thread and have the progress reported back or use a delegate to do the UI updates... oh joy, what fun that'll be.....

-tg

techgnome
May 20th, 2009, 04:45 PM
DeanMc - you posted while I was composing and looking up some stuff. Yeah, I thought about that too... but I was trying to avoid doing that. At that point, I would just create it as a WinForm... the point of this exercise was to learn more about WPF.... the more I think about it, the more I think I may go with the threading and delegate model.... It'll give me a chance to play with something I haven't had much of a chance to do before and learn a few new things in the process. :P

-tg

DeanMc
May 20th, 2009, 04:57 PM
To be honest using a dispatcher with a background thread is the "correct" way to do it that and reworking your logic to be faster. I do think it is strange though, given that WPF applications could be process intensive and by their nature graphically intensive too that there is no helper methods built in to alleviate this problem. Meh, what can you do eh?

techgnome
May 21st, 2009, 09:06 AM
"reworking your logic to be faster" - it's copying files.... I can't make it go any faster.... I tried DoCommand.Copy.GoFaster.... it didn't like it. Something about and unknown object or type.... ;)

Yeah, as I played around with a few things yesterday, it looks like the dispatcher might be what I need... but it seems to have some limitations - mostly it's my current ignorance in the subject, I'm sure I'll be able to find what I need out there.

Thanks!

-tg

DeanMc
May 21st, 2009, 09:52 AM
Try Copy.Files(DontSlowApp)

Anyhoo, it is something i need to look at too, if you get a working sample i would love to see it!

techgnome
May 21st, 2009, 02:28 PM
Hot diggity dawg! I got it!

Here's the setup:

Private WithEvents _myProcess As System.ComponentModel.BackgroundWorker

Private myAddProgressDelegate As Func(Of String, ListViewItem)

_myProcess is the background worker that does the heavy lifting....

then I have a function that remains on the main thread that updates the UI:


Private Function AddProgress(ByVal progressText As String) As ListViewItem
Dim newListItem As New ListViewItem With {.Content = progressText}

Me.uxStatusListView.Items.Add(newListItem)
Me.uxStatusListView.SelectedItem = newListItem
Me.uxStatusListView.ScrollIntoView(newListItem)

Return Nothing
End Function


In a button click I create my BGW, create my delegate, and fire off the process:
[/code]

_myProcess = New System.ComponentModel.BackgroundWorker

myAddProgressDelegate = AddressOf AddProgress

_myProcess.RunWorkerAsync()
[/code]

Then I have another method that invokes my delegate when I need it:

Private Sub dispatchStatus(ByVal progressText As String)
Me.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Background, myAddProgressDelegate, progressText)
End Sub


Then, last, and least, from the _DoWork event of the BGW, I call the dispatchStatus method:
dispatchStatus("Copying files...")


And viola! I get a nicely responsive UI that displays what it is doing as it is doing it. no more lock ups!

I had found a simpler solution:

uxStatusListView.Dispatcher.Invoke(Windows.Threading.DispatcherPriority.Background,Function() uxStatusListView.Items.Add(progressText )

But the problem with it is that it wasn't scrolling the list, so once it added items down past the bottom.... you couldn't see what was going on.... that was the tricky part....

Thanks for all the help guys! I'll be closing this now, so that some one else can use the info.

-tg

DeanMc
May 21st, 2009, 03:56 PM
Very nice!

mtapia
Jul 20th, 2009, 02:03 PM
Also, I know this is crazy but what happens if you add a reference to system.windows.forms.dll. You could then use DoEvents() via System.Windows.Forms.Application.DoEvents() or at least it SHOULD work!

I tried this. I opened up a new window from a main window and while that window was loaded, I looped through the same DoEvents command. However, in the new window, I can not input any thing (nor in the main window)...seems like DoEvents hung up my keyboard. Any thoughts?