I'm having a problem with RenderTargetBitmap, in that I can't get it consistently grab an updated render after I change bound properties on a background thread.
Here is what I have:
// Update a property on an INotifyPropertyChanged view model
// This runs on a background thread
viewModel.SomeBoundProperty += 10;
// Flush dispatcher queue (from http://stackoverflow.com/a/2596035/612510)
_lcd.Dispatcher.Invoke(() => {}, System.Windows.Threading.DispatcherPriority.Loaded);
// Render the updated control
_lcd.Dispatcher.Invoke(() =>
{
_lcd.Measure(new System.Windows.Size(240, 160));
_lcd.Arrange(new System.Windows.Rect(0, 0, 240, 160));
_lcd.UpdateLayout();
_renderTarget.Render(_lcd);
}
Alas, approximately half the time I'm getting the render before the control is updated with the new value, and the other half it updates correctly.
From what I understand WPF dispatches property change notifications automatically to the UI thread. How can I ensure that these dispatched notifications are all processed before doing the render? This code works fine if I make sure SomeBoundProperty is updated on the Dispatcher thread, but that is less than ideal for this particular application.
Any suggestions?
Some trial and error has me figuring that property change notifications are dispatched at the DispatcherPriority.Background priority, so changing the flushing line to this:
// Flush dispatcher queue
_lcd.Dispatcher.Invoke(() => {}, System.Windows.Threading.DispatcherPriority.ContextIdle);
...looks like it fixed the problem. DispatcherPriority.ContextIdle is one level below DispatcherPriority.Backgound. The render now updates consistently every time.
Related
This may be incredibly simple but for the life of me I can't figure out how to achieve it.
I have a notification system working through websockets and every time a new notification gets sent, I add it to an array in state and re map to include the notification. each notification has its own timeout so I'm able to remove them programatically... but.... each notification also has an animated logo which basically resets every time a new notification appears. This happens due to the array being mapped each time and therefore the animation begins again as it's essentially a new notification... so I end up with several notifications all having their animation in sync.
Ultimately i'd like to be able to receive a new notification, render it and not touch set state... is this possible?
I'd say it depends on how exactly you are doing animations. Is it purely CSS animation or JS-driven one? Usually such behavior would mean that components are being remounted on every update. This can be changed by providing consistent key attribute, such as a unique id that identifies a notification.
If you make sure your existing notifications have the same keys as before, they shouldn't rerender when you add a new notification to your array in state.
Here's a codesandbox in which you can generate new notifications without triggering re render for existing notifications.
I have a property like this.
public double RollDegrees
{
get
{
return rollDegrees;
}
set
{
if (rollDegrees != value)
{
rollDegrees = value;
OnPropertyChanged(PROPERTY_NAME_ROLL_DEGREES);
}
}
It is binding to a xaml control and the UI updates perfect in normal conditions.
This property is updated on NON-UI Thread but as far I know it not neccesary to put the update on a Dispatcher.BeginInvoke with plain properties.
But when the app is running a busy update on the UI thread (map control moving fast with updates) The UI Binding of this property is not updated, then when the busy update finish the property again updates the UI.
But if I put
Application.Current.Dispatcher.BeginInvoke((Action)(() =>
{
RollDegrees = (OperationEntity as Level).RollDegrees;
}));
Then the UI works perfect
Any hints of why this is happening?? Maybe something in the busy update?? Or this is a normal behaviour when the UI Dispatcher is full and busy??
All UI elements should be updated only in UI thread. Each thread has it's own dispatcher. In case if you need update UI from non-UI thread, you should call Application.Current.Dispatcher.BeginInvoke(). Hence it is normal behavior.
In the first scenario, you're updating the property, but not from the UI thread. Hence the delay caused till the UI thread comes into action. When you're using the Application.Current.Dispatcher.BeginInvoke(), the UI is updated immediately.
So if you want to reflect some changes related to UI from a different thread, use Application.Current.Dispatcher.BeginInvoke().
Read more # https://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.begininvoke(v=vs.110).aspx
I started to use Prism (5.0) some days ago and now I run into a problem I cant solve myself.
I used the quickstart "viewswitchingnavigation".
So I have a shell with a navigation and a main panel/region.
Navigation region holds some radiobuttons to switch the views that are split into view and viewmodel with a service based model.
View A shows a collection of documents with a button each to open a new view B for this document's details.
A button in this detailview should start a part of code. This code moves some data what takes quite a while since the data need to be parsed. Since the user shouldnt wait for a nonreactiong window I want to show some information about the status of the running code. (Example: Getting data 1/3012, which is updated with each new got data piece). This code gets one piece of data at a time so I could send(?) some information to the view to update the status there (if I knew how)
So.
How to implement the button that starts the "external" code?
How to access the current view (e.g. to change the status shown in a loader or in a textbox like destribed above.
You could use a BackgroundWorker class which has built-in progress reporting functionality. Alternatively, you could create your own asynchronous data retreiving mechanism by using async / await and Tasks.
For your progress displaying view you could use the State-Based Navigation provided by Prism. You could display an on-top view with a progress bar or text box showing the progress. As usual, the UI elements of the view should be bound to the view model's properties. To update these UI properties you should use Dispatcher.Invoke(), or SynchronizationContext, or similar sync mechanism, because your progress reporting method (or event) will be called by a background thread.
If you could post your code, then my answer could be more specific.
Not exactly sure what you aim for, though here are two options:
Shall the data begin to be fetched when the View/Windows gets loaded? Then your ViewModels have to implement INavigationAware interface and INavigationAware.OnNavigatedTo (and From) Method). You can mark that method as async to be able to use await within it.
public async void INavigationAware.OnNavigatedTo(NavigationContext navigationContext)
{
await LongRunningTask();
}
public async Task LongRunningTask()
{
foreach(var dataChunk in allData)
{
// Status Text is a property which raises OnPropertyChanged when changed and which you databind to a textbox
StatusText = string.Format("Getting Data {0}", dataChunk.Description);
await ProcessDataChunk(dataChunk);
}
}
Or if you want it happen on an user action, you do it via an async ICommand.
private ICommand processCommand;
public ICommand ProcessCommand)
{
return processCommand??(processCommand = DelegateCommand.FromAsyncHandler(this.LongRunningTask));
}
private void Window_ContentRendered_1(object sender, EventArgs e)
{
StatusLabel.Text = "Doesnt show up until the sleep is over...0_0";
System.Threading.Thread.Sleep(2000);
}
I want to ask why does it heppend and only then a solution. thanks all
Issue is you are sleeping on UI thread.
After first line execution you slept on UI thread but it's UI thread responsibility to refresh UI (UI thread refreshes UI on Render dispatcher priority). Hence, you see no update after first line execution because UI thread never gets time to execute render priority items queued on dispatcher.
Ideally, you should use DispatcherTimer to wait on UI thread for certain interval of time and then update once interval time is elapsed.
Also, either you should move the long running task on background thread using backgroundWorker and sleep on that thread instead on UI thread. Also as SLaks suggested you can use async/await to get desired result.
However, quick and dirty solution would be to dispatch empty delegate on UI thread with Dispatcher priority set to Render just before you slept on it so that UI refresh part gets executed before thread falls in sleep state.
StatusLabel.Text = "Doesnt show up until the sleep is over...0_0";
lbStatus.Dispatcher.Invoke((Action)(() => { }), DispatcherPriority.Render);
Thread.Sleep(2000);
Idea here is once you queue empty delegate on UI dispatcher with render priority, it will execute all pending items with priority higher or equal to Render. Since, UI refresh is done on on Render priority, UI will be refreshed and you will see update in label content on GUI.
I need to run some code (let's say to show message box) right after the view is displayed. I tried to override OnInitialize, OnViewLoaded or OnViewAttached but it's always the same. The View is not fully displayed yet.
I use some animation when displaying view but at the same time need to load some data into grid. If I put data load into OnInitialize, OnViewLoaded or OnViewAttached the animation is not smooth as it's kind of happening the same time when loading data.
Any thoughts?
Give something like this a try - use a couroutine to wait for the animation to complete before binding the grid:
private IEnumerator<IResult> ViewModelStartup()
{
yield return new WaitForAnimation("AnimationName");
BindData();
}
(note - you can load the data async, but just don't assign it)
Then when your form loads:
private void OnViewAttached()
{
Coroutine.BeginExecute(ViewModelStartup(), new ActionExecutionContext() { View = this.GetView() });
}
(the code above might not be 100%... I think View must be FrameworkElement in ActionExecutionContext so cast as needed or create a wrapper class)
The implementation of the WaitForAnimation coroutine would search the view for a named animation and wait for it to complete before firing the callback. You should probably just fire the callback if the animation could not be found. The couroutine could be used on multiple views.
(Coroutines must implement IResult have a look at the docs on the CM codeplex site for info)
http://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation