Why doesn't my Grid update when I add children in dispatcher? - c#

I'm running a fairly simple task with the kinect, just trying to display data streams using the polling method. I am running all of my processing on a backgroundworker, and using dispatcher to update the UI.
The code below works fine for depth and color streams that write to a bitmap in the dispatcher. However, displaying the skeleton requires a Grid with children (polylines). This code runs without error, but does not update the UI to show the line. What do I need to do to make the UI refresh the Grid and show the child objects?
this._SkeletonGrid.Dispatcher.BeginInvoke(new Action(() =>
{
joints = new[] { JointType.Head, JointType.ShoulderCenter, JointType.ShoulderLeft, JointType.ShoulderRight, JointType.ShoulderCenter };
this._SkeletonGrid.Children.Add(CreateFigure(skeleton, userBrush, joints));
}));
_SkeletonGrid is the xaml Grid object, CreateFigure returns a polyline.

Related

How can i handle LayoutUpdated or stop a control rendring in WPF?

i want to cancel or stop or handle rendering(or drawing) a WPF Element for lower cpu usage(cancel all forever animations and rendering in background or collapsed visibility items for use best performance in my app).
i read all Optimizing WPF Application Performance
void MainWindow_LayoutUpdated(object sender, EventArgs e)
{
e.Handled = true;//can i handle an object rendering?
}
LayoutUpdated is not going to help you at all. It is an event that fires on all UI elements associated with a Dispatcher after a full layout pass has completed, meaning the work is already done.
You have a few options, depending on what your goal is.
Hide the Element
If you don't want the element to be visible or perform any layout, then you can set its Visibility property to Collapsed. It should skip most of its layout logic and all of its rendering logic while it is collapsed.
Remove the Element
Removing the element from the visual tree is a sure way to keep it from doing anything. You can add it back later if you need to. The process for how to do this depends a lot on how your code is currently setup.
Reduce the Performance Cost of the Element
If the element is expensive because it is doing a lot of work, you could look into optimizing it in general, and/or look into disconnecting its event listeners and bindings during the time when you don't want it doing work.
Pause UI Processing
If you want to temporarily pause all UI processing while you perform some operation (to prevent reentrancy), you can use Dispatcher.DisableProcessing. Note that this will disable UI processing for the entire thread, not just the processing of a specific element.
using (Dispatcher.DisableProcessing())
{
// Do work while the dispatcher processing is disabled.
}
A Static Picture of the Element
If you want to permanently disable all processing of an element, I don't know of a way to do that while still keeping it visible on the screen. However, you could use a RenderTargetBitmap to render the element to an ImageSource and then replace the original element with an Image element that has its Source property set to the bitmap.
RenderTargetBitmap target = new RenderTargetBitmap((int)element.RenderSize.Width, (int)element.RenderSize.Height, 96.0, 96.0, PixelFormats.Default);
target.Render(element);
image.Source = target;
Now you basically have a "picture" of the element in place of where the original element was.

Making animations run smoother

My WPF program's storyboard animations stutter ruining user experience (for example on adding larger number of items to ObservableCollection and ListBox being updated).
My idea was to make animation run smoother by dispatching them with higher priority so I tried
Storyboard sb = new Storyboard();
//all animations
this.Dispatcher.Invoke(() =>
{ sb.Begin();
}, System.Windows.Threading.DispatcherPriority.Send);
I thought there would be difference between "Send" as highest priority and "SystemIdle" as lowest, but there isn't.
I hope there is small problem in my understanding of the dispatcher and there is a simple fix, but I am open to any ideas of improving animation performance.
EDIT
Implemented on each animated control RenderTargetBitmap which takes screenshot on animation start and replaces complicated visual tree with one image control, and switches it back when animation is complete
Populating listbox that ruins my animation in Dispatcher with SystemIdle priority
Set framerate to 30
Checked in perfmon and nothing seems software rendered, RenderTier is 2
If I disable populating listbox completely everything runs smoothly
Listbox is populated like this
Task.Factory.StartNew(() =>
{
List<MyData> _f = new List<MyData>();
//populate _f
Dispatcher.BeginInvoke(new Action(() => {
_MyCollection.Clear();
_MyCollection.AddRange(_f); //Adding items without raising events *
}), DispatcherPriority.SystemIdle);
}
*I even use addRange for ObservableCollection from ObservableCollection : calling OnCollectionChanged with multiple new items

I want to force a render, but only draw as fast as possible (InvalidateVisual / CompositionTarget.Rendering)

I'm working on a real-time WPF/Silverlight (and soon WP7) visualization component and I'm looking for the best solution to force a redraw of the entire component in a Game-loop style. Redraw should be on-demand, but I don't want to back up the message pump with re-draw calls. Most of the drawing in my component is done using non-WPF primitives (e.g. Bitmap Interop, Direct2D) so my code does not use InvalidateVisual, and as a result, currently looks like this
// Pseudocode, doesnt compile, just to convey the meaning
public void InvalidateElement()
{
if (CurrentlyDrawing)
return;
Dispatcher.BeginInvoke(() =>
{
CurrentlyDrawing = true;
DoDrawInternal();
CurrentlyDrawing = false;
}
}
Ok so this is great. If I call InvalidateElement lots of times I get good responsiveness. However, what I want to do is ensure I can push data to my visualization component as fast as possible but only draw when the component is able to draw, and not keep drawing to catch up with the data once the input stream completes.
No I can't override OnRender, I'm using non-WPF drawing inside WPF ;-)
Basically what I want is something like the old Invalidate() / OnPaint in WindowsForms, or better yet, a game loop in DirectX.
At the moment I get the situation where if I have an external thread that pushes data to the visualization component at a high rate then if I Stop pushing data I get another 20 seconds worth of refreshes to get through before the component stops drawing. I want to stop drawing as soon as data has gone in.
Another idea I had was to handle CompositionTarget.Rendering in the visualization component then implement some sort of rudimentary Queue to push data to and the Rendering event consumes this data as fast as it can.
In Summary
Given a WPF visualization component, V, and a datasource which pushes it data every 1ms, D, how can I ensure that no matter the datarate of D, V draws data at 30FPS (or whatever it can do) and updates itself in chunks, sort of how a game render loop does in DirectX?
When the data stops, V should redraw everything it has up to now in one go. When the data is too fast, V draws larger chunks at a time to compensate.
If you need more information I'd be happy to share it. Right now I've just posted a synopsis to gauge if there are any quick fixes but a fuller Q with code examples can be provided on request.
Best regards,
You might want to consider rendering on the CompositionTarget.Rendering event and throttling on the invalidated state.
Silverlight game loop example (F#):
/// Run game
let runGame () =
let state = gameState.GetEnumerator()
let rate = TimeSpan.FromSeconds(1.0/50.0)
let lastUpdate = ref DateTime.Now
let residual = ref (TimeSpan())
CompositionTarget.Rendering.Add (fun x ->
let now = DateTime.Now
residual := !residual + (now - !lastUpdate)
while !residual > rate do
state.MoveNext() |> ignore
residual := !residual - rate
lastUpdate := now
)
Play the game: http://trelford.com/blog/post/LightCycles.aspx
Read the source: https://bitbucket.org/ptrelford/lightcycles
You can listen to the CompositionTarget.Rendering event, which is triggered right before WPF renders the UI, and do your drawing in there.
Another tidbit.. InvalidateVisuals() is nothing like Form.Invalidate(), as it also causes re-layout which is expensive. If you want something like Form.Invalidate(), then create a DrawingGroup (or bitmap image) "backingStore", place it in the DrawingContext during OnRender(), and then update it whenever you want. WPF will automatically update and repaint the UI.
Have you thought of using a dispatch timer running at 30FPS, then take a snapshot of the current data and rendering it at each timer tick? If you want to avoid redrawing if nothing has changed, you can simply keep timestamps for LastChanged and LastRendered, only performing an actual redraw if LastChanged > LastRendered. Basically updating the data and rendering the data are decoupled from one-another; the main trick is making sure you can somehow get a coherent snapshot of the data when the rendering thread wants to render it (i.e. you'll need some sort of locking.)
I was recently working with a project that required a game loop like style. Although my example is purely in F#, you can figure it out how you can do that way in C# too, may be use some interop code to initialize the timer and hooking up events as given in this below link,
http://dl.dropbox.com/u/23500975/Demos/loopstate.zip
The sample doesn't show how to redraw, it just updates the underlying stock data for every 500ms, It should pretty much work for any kind of drawing mechanisms with WPF. The core idea is to use composable events, in F# an event is a first-class citizen + an IObservable (reactive extensions for C#), so we can easily compose functions that in-turn return a set of events or a single event. There is a function Observable.await, which takes in an Observable and also has a state to return.
eventSource
|> Observable.await(fun (t:State.t) e ->
// return the modified state back on every check or in the end
match e with
// start button click
| Choice1Of3(_) ->
{t with start=true}
// stop button click
| Choice2Of3(_) ->
{t with start=false}
// timer tick event,
| Choice3Of3(_) ->
if t.start = true then
handleStockUpdate(t)
else t
) (state)
I just used some of FP terms here, but it should work just fine with normal C# (OO) way of doing things here.
Hope this helps!
-Fahad
I'm not sure why you would use WPF for your front-end if you're drawing using non-WPF elements and require the Invalidate() method that was provided by WinForms? Can't you just switch the UI to use WinForms?

Wait for animation, render to complete - XAML and C#

I have a situation where I am animating part of my XAML application, and I need to wait for the animation AND rendering to complete before I can move on in my code. So far the tail end of my function looks like:
ProcExpandCollapse.Begin();
while (ProcExpandCollapse.GetCurrentState() != ClockState.Stopped) { }
}
Which, in theory, will wait until the animation is finished. But it will not wait until the rendering is finished - the thread drawing the application might still not have re-drawn the animation.
The animation is expanding a UIElement, and then the next part of my code uses it's rendered size to do some things. My question then is, how do I wait until my UI Element is re-rendered before moving on?
I finally found an answer (although I had to pay for consulting services)! Essentially what I ended up doing was putting the bit of code which uses the rendered controls on the control dispatcher's queue with very low priority, so that it naturally renders before handling that task. For example:
mycontrol.Dispatcher.BeginInvoke((Action)delegate{textbox1.Text = "Grazie";});
mycontrol.Dispatcher.Invoke((Action)delegate{GetScreenshot();}, DispatcherPriority.Background);
The code will then procede after GetScreenshot is called and finished, which will be after the rendering is completed (because rendering has higher priority than background).
The Storyboard object has a 'Completed' event you can subscribe to. It will be called when the animation is done. This what you are looking for?
Basically I think you want "ProcExpandCollapse.Completed +=" (then hit tab a view times, VS will generate a snippet for you)

Draw image on a form from a separate thread

I am currently working on a Windows.Forms application. It's basically a simple motion detection problem.
I have a button on a form, that when pressed launches a background worker that does the following :
Fetch an image from disk
Create a new bitmap, to be used as the buffer.
Perform Motion Detection
From the results of Motion Detection, update the buffer (using the buffer's drawing surface)
Fire the Progress Changed Event with an argument consisting of a clone of the buffer, basically (sender as BackgroundWorker).ReportProgress((Bitmap)buffer.Clone())
In the Progress Changed Event, I then draw the buffer to screen.
if (!PnlImage.IsDisposed)
PnlImage.CreateGraphics().DrawImageUnscaled(buffer, 0, 0);
I can't help wondering if this is the best way to draw the updated image on the screen. Can anyone suggest any improvements I can make?
Thanks.
EDIT :
I have since updated the program to use the .NET Framework 4, and we're no longer using a BackgroundWorker. Instead, we are now using the System.Threading.Tasks namespaces, and using Invoke to update the background image from within the task.
Thanks to all replies.
I believe the root of any problems you may be experiencing is the fact that any GUI updates must be done on the UI thread. You cannot safely update the UI from another thread. So, basically, you need to do something like the following (I'm just changing the background color as an example, but you can do whatever you like):
private void SomethingCalledFromBackgroundThread()
{
panel1.Invoke(new DoUpdatePanel(UpdatePanel), Color.Blue);
}
private delegate void DoUpdatePanel(Color aColor);
private void UpdatePanel(Color aColor)
{
panel1.BackColor = aColor;
}
============ Update =======>
#Ash you have mischaracterized my answer. I did not say to call Invoke from within ProgressChanged. #Jean keep in mind that ReportProgress/ProgressChanged is being run asynchronously--which is why you find yourself making a clone of your image. This would not be necessary if you use Invoke from within your background thread, rather than ReportProgress.
I'm not sure if this is strictly true but I'm sure you can't cross thread GUI/Control operations on a separate thread as it is handled by default on a dedicated GUI thread.
I tried to do something similar to this before and in the end i decided on an entirely different approach to it as setting a property to false was the worst way to get it to work.
The ProgressChanged and RunWorkerCompleted Events allow you to update the UI directly. It is only the DoWork event handler that you must not access the from. See MSDN:
You must be careful not to manipulate
any user-interface objects in your
DoWork event handler. Instead,
communicate to the user interface
through the ProgressChanged and
RunWorkerCompleted events.
This is one of the major benefits in using the BackgroundWorker over creating your own thread. So TheObjectGuy is not correct, you do not need to use BeginInvoke/Invoke in ProgressChanged.
As long as your image is not too large, cloning it should not cause any serious performance issues. Run some performance tests with bigger images if you have concerns.
Otherwise, to avoid tricky synchronization issues such as using lock, I think making a clone of the image is a good way to keep things simple.
Using the ProgressChanged event is fine. What is not fine is drawing directly to the screen. Your image will disappear when you minimize and restore the form. The workaround is simple:
PnlImage.BackgroundImage = buffer;

Categories

Resources