Why Silverlight popup hangs while doing calculations? - silverlight

I have create a custom date time control in silver light , in my silver light custom control there is property names "EditDate" this date is set with the help of binder , and basically doing two way binding , when i set edit date from date time picker , it well set my external property and while setting external property there is a setter event which performs some calculations , now the issue is while the calculation is in progress my date time picker popup remain opened , is there any way i can hide it immediately after setting "EditDate" ?
Thanks
Aman.

I think the calculations are freezing up the UI thread. Put the calculations in a BackgroundWorker so the UI can be updated as the calculations are being processed.
var bw = new BackgroundWorker();
//Will fire when backgroundworker starts
bw.DoWork += (snd, arg) =>
{
//Do your calculations here
CalculationsFunction(param1, param2)
//Cannot access UI elements here
};
//Will fire when backgroundworker finishes
bw.RunWorkerCompleted += (s, arg) =>
{
//Can access the UI here again if needed
if (arg.Error != null)
{
//Show message if error
}
else
{
//Update UI here if needed
}
};
//Begins running the background worker
bw.RunWorkerAsync((this.DataContext as Iteration));

Related

Responsive UI in async drawing

I am trying to create a drawing with 5000 Shape objects in a background thread on a canvas.
I use the asyn-await pattern:
async void CreateDrawingAsync()
{
await Task.Run(() => CreateDrawing()).ConfigureAwait(false);
}
void CreateDrawing()
{
DrawObjects = new ObservableCollectionEx<DrawObject>();
// or: DrawObjects.Clear();
RaisePropertyChanged("DrawObjects");
// etc ... etc ...
}
ObservableCollectionEx means I use an extension of ObservableCollection to add an object to the collection via the Dispatcher.
When I start CreateDrawingAsync in the Loaded event of the Window (in the ctor of Data) the UI is unresponsive.
Using DispatcherPriority.Background the items are added one by one in the UI, but also in that case, the UI is unresponsive.
Loaded += (object sender, RoutedEventArgs e) =>
{
DataContext = new Data(2000, 1000, 1000);
};
1) I expected the background thread would resolve the unresponsive UI issue, what am I overlooking?
2) Why does RaisePropertyChanged("DrawObjects") (see code above) have no effect? I would have expected the drawing would be cleared due to the propertychanged.
You should not do UI operations on a background thread. This includes:
Drawing on a canvas.
Raising PropertyChanged notifications.
Creating or updating an ObservableCollection.
Creating a fake-UI component like ObservableCollectionEx that just forwards all its work to the UI thread doesn't gain you anything.

show Loading animation in wpf

I am trying to show a loading animation when a page is taking time to load. I am loading multiple/several user controls depending on user request using Thread. I have tried the following ways
this.Dispatcher.BeginInvoke(new Action(LoadSecondPageData), DispatcherPriority.Background);
when I am using this it is making my Loading animation freeze until the page loads
I also tried BackgroundWorker concept Loading animation is working here, but it is not allowing to load the usercontrols and giving an error.
Error: "The calling thread must be STA, because many UI components require this."
You need to start the animation on the main UI Thread using Dispatcher.BeginInvoke, but any loading of data should happen on a background thread so that the animation doesn't freeze.
When the data is loaded, any final updates that effect dependency properties need to be marshalled onto the UI thread using Dispatcher.BeginInvoke once more.
I also tried BackgroundWorker concept Loading animation is working here, but it is not allowing to load the usercontrols and giving an error.
This is by design, you're not allowed to touch anything on the UI side in your background thread, as it will not be STA. Instead, bind your progress indicator to properties that the thread could modify, and then the progress indicator will get the update via the INotifyPropertyChanged event.
For example, if you had a ProgressBar bound to ProgressPercentage, or an indeterminate busy indicator bound to IsBusy:
In XAML:
<ProgressBar x:Name="StatusBar"
Maximum="1" Value="{Binding ProgressPercentage}" />
In Code:
using (var backgroundWorker = new BackgroundWorker())
{
backgroundWorker.DoWork += (s, ex) =>
{
IsBusy = true;
StatusText = "Pretending to do something...";
for (int i = 0; i < 100; i++)
{
ProgressPercentage = (i + 1)/100.0D;
Thread.Sleep(100);
}
};
backgroundWorker.RunWorkerCompleted += (s, ex) =>
{
IsBusy = false;
StatusText = "Export Complete.";
};
backgroundWorker.RunWorkerAsync();
}
The background thread will do its work, the UI thread will not block while waiting, and your progress indicator will update as it goes.

wpf BackgroundWorker - Regarding updating UI

I use a browse for files dialog to allow a user to select multiple images. If a lot of images are selected, as expected it takes a bit. Below is an example of what I do with the selected images. I loop through the filepaths to images and create an instance of a user control, the user control has an Image control and a few other controls. I create the instance of this control then add it to a existing stackPanel created in the associating window xaml file. The example just below works fine, but I'm trying to understand BackGroundWorker better, I get the basics of how to set it up, with it's events, and pass back a value that could update a progress bar, but because my loop that takes up time below adds the usercontrol instance to an existing stackPanel, It won't work, being in a different thread. Is BackGroundWorker something that would work for an example like this? If so, what's the best way to update the ui (my stackpanel) that is outside the thread. I'm fairly new to wpf and have never used the BackGroundWorker besides testing having it just update progress with a int value, so I hope this question makes sense, if I'm way off target just let me know. Thanks for any thoughts.
Example of how I'm doing it now, which does work fine.
protected void myMethod(string[] fileNames) {
MyUserControl uc;
foreach (String imagePath in fileNames) {
uc = new MyUserControl();
uc.setImage(imagePath);
stackPanel.Children.Add(uc);
progressBar.Value = ++counter;
progressBar.Refresh();
}
}
below this class i have this so I can have the progressBar refresh:
public static class extensionRefresh {
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement) {
uiElement.Dispatcher.Invoke(DispatcherPriority.Background, EmptyDelegate);
}
}
Check out this article on
Building more responsive apps with the Dispatcher
Now that you have a sense of how the Dispatcher works, you might be surprised to know that you will not find use for it in most cases. In Windows Forms 2.0, Microsoft introduced a class for non-UI thread handling to simplify the development model for user interface developers. This class is called the BackgroundWorker
In WPF, this model is extended with a DispatcherSynchronizationContext class. By using BackgroundWorker, the Dispatcher is being employed automatically to invoke cross-thread method calls. The good news is that since you are probably already familiar with this common pattern, you can continue using BackgroundWorker in your new WPF projects
Basically the approach is
BackgroundWorker _backgroundWorker = new BackgroundWorker();
// Set up the Background Worker Events
_backgroundWorker.DoWork += _backgroundWorker_DoWork;
_backgroundWorker.RunWorkerCompleted += _backgroundWorker_RunWorkerCompleted;
// Run the Background Worker
_backgroundWorker.RunWorkerAsync(5000);
// Worker Method
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Do something
}
// Completed Method
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Doing UI stuff
if (e.Cancelled)
{
statusText.Text = "Cancelled";
}
else if (e.Error != null)
{
statusText.Text = "Exception Thrown";
}
else
{
statusText.Text = "Completed";
}
}
Using a BackgroundWorker alone won't solve your issue since elements created during the DoWork portion will still have originated from a non-UI thread. You must call Freeze on any objects you intend to use on another thread. However only certain UI objects will be freezable. You may have to load in the images as BitmapImages on the background thread, then create the rest of your user control on the UI thread. This may still accomplish your goals, since loading in the image is probably the most heavyweight operation.
Just remember to set BitmapImage.CacheOption to OnLoad, so it actually loads up the image when you create the object rather than waiting until it needs to be displayed.

WPF image visibility is not changing

I have the following method in my WPF project (.net 4):
private void MyMethod(){
imgMyImage.Visibility = Visibility.Visible;
DoWork();
imgMyImage.Visibility = Visibility.Collapsed;
}
The image is in a DockPanel, and I want it to appear while the "DoWork()" method is being executed, but it does not change state until after the "MyMethod()" method exits. Can someone explain how to make this work correctly?
Thank you for any help.
Your "DoWork" method is blocking the UI thread. Until it completes, nothing in the UI will change (and the UI will remain unresponsive).
A better option is to push the DoWork into a background thread. For example, using the new Task framework in .NET 4, you could write this as:
private void MyMethod()
{
imgMyImage.Visibility = Visibility.Visible;
// Create a background task for your work
var task = Task.Factory.StartNew( () => DoWork() );
// When it completes, have it hide (on the UI thread), imgMyImage element
task.ContinueWith( t => imgMyImage.Visibility = Visibility.Collapsed,
TaskScheduler.FromCurrentSynchronizationContext() );
}

WPF: How to apply a change to an Opacity/Background immediately? (WPF analog to WinForms Control.Update() method?)

I have a WPF app, upon clicking a button, the app goes into a calculation that can take 4-10 seconds. I'd like to update the opacity of the background and show a progress bar, during that operation.
To do that, I use this code:
this.Cursor = System.Windows.Input.Cursors.Wait;
// grey-out the main window
SolidColorBrush brush1 = new SolidColorBrush(Colors.Black);
brush1.Opacity = 0.65;
b1 = LogicalTreeHelper.FindLogicalNode(this, "border1") as Border;
b1.Opacity = 0.7;
b1.Background = brush1;
// long running computation happens here ....
// show a modal dialog to confirm results here
// restore background and opacity here.
When I run the code, the background and opacity doesn't change until the modal dialog appears. How can I get those visual changes to happen right now, before the calculation begins? In Windows Forms there was an Update() method on each control, that did this as necessary, as I recall. What's the WPF analog?
What if you would do long running computation in the background thread? Once they are done dispatch results back to UI thread...
Honestly, I suspect there is nothing else there, that can solve your problem. Maybe nested pumping will do the trick, but I really doubt it.
Just in case this reference is helpful: Build More Responsive Apps With The Dispatcher
Use the DoEvents() code as shown here:
http://blogs.microsoft.co.il/blogs/tamir/archive/2007/08/21/How-to-DoEvents-in-WPF_3F00_.aspx
My actual code:
private void GreyOverlay()
{
// make the overlay window visible - the effect is to grey out the display
if (_greyOverlay == null)
_greyOverlay = LogicalTreeHelper.FindLogicalNode(this, "overlay") as System.Windows.Shapes.Rectangle;
if (_greyOverlay != null)
{
_greyOverlay.Visibility = Visibility.Visible;
DoEvents();
}
}
private void DoEvents()
{
// Allow UI to Update...
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
new Action<object>((arg)=> {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue= false;
}), f);
Dispatcher.PushFrame(f);
}

Resources