I'm trying to make a listbox that display pictures from internet. The items are provided by binding itemsource to a model that contain the URL of the image and some other properties (title, desc, etc...).
Unfortunately, the list is very slow to load because WPF is trying to download all pictures from the web before showing the list and it makes the application freeze for 15 to 25 sec.
I've read that I should load the picture in an other thread but I don't know where I should do it and how ? Is it better to load all pictures directly in the model (by creating a thread pool only for that - but the problem is that it's not really part of the model/modelview) or is that better to create a background thread that will update directly the list when it has data ?
Thanks !
The easy way is to just just set the Binding.IsAsync property like this:
<Image ImageSource="{Binding propertyThatComputesImageSource, IsAsync=true}" />
Each access to propertyThatComputesImageSource will be done from a ThreadPool thread. If the thread creates the image with ImageCacheOptions.OnLoad, it will block until the image is loaded. So the UI will start up immediately and images will be loaded in the background and appear when they are available.
Binding.IsAsync is a good solution for ten or twenty images, but is probably not a good solution if you have hundreds of images and the load delay is long, since you could end up with hundreds of threads. In that case, load the images outside of databinding entirely by using ThreadPool directly:
ThreadPool.QueueUserWorkItem((state) =>
{
foreach(var model in _models.ToArray())
model.ImageSource = LoadOneImage(model.ImageUrl);
});
This may need to be extended with a Dispatcher.Invoke or two if the model's properties are DependencyProperty, since they can't be accessed from a separate thread.
This technique can be extended to spawn a fixed number of workers to load images and break the work up between them so multiple image downloads are happening, but the number of simultaneous downloads is limited so you don't end up with hundreds of threads.
A very simple approach would be to use a System.ComponentModel.BackgroundWorker (more info) in the view model. Here's a trivial example:
using (BackgroundWorker bg = new BackgroundWorker())
{
bg.DoWork += (sender, args) => FetchImages(viewModelObjectsNeedingImages);
bg.RunWorkerAsync();
}
The BackgroundWorker also makes it very convenient to cancel the background task.
You might also want to look at UI virtualization.
You can use this asynchronous observable collection to be able to bind your data source to your ListBox and still be able to load your data in another thread.
For an example on how to write such a thread, take a look at the BackgroundWorker documentation.
Also, you might want to consider lazy loading of your images, that is, only load the ones that are visible and a couple more at any time. This way, you gain two benefits: don't have to block the UI while fetching the images in your thread, and you can reuse your collection to only hold a few images at a time, preventing filling up the memory with lots of images at once if you plan on displaying, say, a couple of thousand. Take a look here for details on how such virtualization could be implemented.
Thanks to all of you !
All solutions should work :) In my case using IsAsync on the image of the ListBoxItem is good enough (at most there are 50 items). Actually, it's not retrieving the image from a network which was taking too much time !
Unfortunately my problem was somewhere else... It's related to a bug with proxy detection in .NET 3.5 which cause the application to load very slowly :
If there isn't any your_application_name.exe.config file in the application folder with the following code - .NET can take a lot of time to detect the proxy which freeze the application the first time that it accesses to a network :
<configuration>
<system.net>
<defaultProxy enabled="false"/>
</system.net>
</configuration>
Related
Can I create UI content with async methods? I was trying to extract data from files and visualize them in the async void. But I caught this error
The application called an interface that was marshalled for a different thread
I want to create multiple items in another thread and show progressBar while it is running. How should I do it?
UPDATE
I am trying to create collection of items and put them like children to StackPanel:
SomeViewModel.cs - class of home page
ObservableCollection<NoteRepresentation> result = new ObservableCollection<NoteRepresentation>();
await Task.Run(() =>
{
foreach (var item in DataTransit.Notes) result.Add(new NoteRepresentation(item));
}
NoteRepresentation.cs - userControl class
public NoteRepresentation(Note note)
{
//some code
this.DataContext = this;
this.InitializeComponent();
}
I want to create multiple [UI] items in another thread and show progressBar while it is running. How should I do it?
This is not possible.
It is possible to load the data for those UI controls in another thread, or to do it asynchronously. But it is not possible to create the UI controls themselves on another thread.
Normally, this is not a problem, since you should not be creating thousands of UI controls to display to the user anyway - no user could reasonably interact with thousands of UI controls. If you find yourself in this situation, you'll need to use data virtualization, which is a way of pretending to create the UI controls but in reality they're only created as needed (e.g., when the user scrolls).
Alternatively, you can rethink the UI design completely. Is it really useful for the user to be able to scroll through all these values? Would a paging design be better? If there are really thousands of these, perhaps a filter is necessary?
I want to run long lasting methods, even containing time consuming dlls, while a Spinner GIF is rotating.
OK, the most accepted solution is to run these methods in a BackgroundWorker while the GIF is shown in the main thread and I have already done, successfully, it but… but I am still curious to know if it is really impossible to do do the other way round !
This would simplify the calls to those methods, especially if they have arguments and return values, avoid the use of Invoke if they contain Labels to show the working progress, etc…
I have spent quite a lot of time browsing the Web but all the suggested solutions don’t work for me: as soon as the program calls my methods the Spinner stops rotating and resume working only when the methods end.
Ciao and thanks for any suggestion.
DONE!!
Thanks to the Camilo Terevinto sentence “You cannot do UI work on a non-UI thread” I asked myself if it was not possible to create the PictureBox that holds my spinning GIF in another thread and…
I created a new borderless Form (named frmSpinner) with inside a PictureBox running the Spinner.gif.
Then I used, in the main Form with the long running methods, a BackgroundWorker that, in the DoWork event, has a frmSpinner.Show().
Now the Spinner rotates endless without interrupting and resuming.
I have still to solve the problem how to place the Spinner Form on the right position on the main Form but, with the help of the PointToScreen method, it shouldn’t be to difficult.
Ciao and thanks for the suggestion.
Dealing explicitly with threads in a WPF/c# project is not canonical, unless you have something very specific to do, using Tasks is the modern way.
You can have a background task, started with for instance:
Task.Run(() =>
{
// blocking methods running outside UI thread
var newPropValue = //... update a UI property
Application.Current.Dispatcher.Invoke(() =>
{
//Running in UI thread.
PropValue = newPropValue;
});
});
With this pattern you can remove all the heavy/blocking work from the UI thread and have a flowing UI experience.
EDIT 1 :
Apparently, i have started to achieve a 3D rendering in WPF environment in an incorrect way. Ofc there is a solution for my question here below, but i suggest to read the update of Sheridan's answer and use his recommendations to achieve this. It's not only secure, but also better for performance. Although it's a bit complex to understand it, but once you understand it, you can start rendering multiple 3D applications in WPF.
Thanks for your assistance Sheridan !
Question ;
i am quite new in WPF, and i want to design a continuous rendering (like in gaming applications) with WPF. I am using multithreading to provide a better UI control (start/stop button fe). Or the event could be disposed due of using an infinite loop to render the 3D world.
But, my problem is that when running the program, i get an Invalid operation was unhandled error. The issue is that there is an object which is a property of the main thread, thus the new thread might not access it.
from XAML file,
<Grid>
<!-- ui controls omitted ... -->
<Viewport3D Name="myViewport" ClipToBounds="True">
<!-- all inits, camera, pos, ... -->
</Viewport3D>
</Grid>
in main class;
/// <summary>this method is done to render the 3D app in other thread.</summary>
private void Runtime(Viewport3D vp) {
System.Diagnostics.Debug.WriteLine("runtime ");
Render3D r3d = new Render3D(vp);
// actual startup
while (keepRunning) {
r3d.Init3D();
}
}
/// <summary>this method toggles the game runtime</summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void StartOrStop(object sender, RoutedEventArgs e) {
keepRunning = !keepRunning;
if (keepRunning) {
buttonStartStop.Content = "Stop";
// thread
t1 = new Thread( () => Runtime(myViewport) );
t1.Start();
}
else {
buttonStartStop.Content = "Start";
t1.Abort();
}
}
The 3DViewport object is initialized in the XAML file. that's why i am passing it to the new thread, that it can create an object which is using that 3DViewport class.
Here below is a sample of the Render3D class.
// constructor
internal Render3D(Viewport3D v) {
currViewport = v;
}
/// <summary>get called in loops to render gfx</summary>
internal void Init3D() {
// clear rendered view
ClearRenderWindow();
// add landscape
AddLandScape();
}
/// <summary>clear window to re-render gfx</summary>
private void ClearRenderWindow() {
ModelVisual3D mv;
// ***** error got caught here below ******
for (int i = currViewport.Children.Count - 1; i >= 0; i--) {
mv = (ModelVisual3D)currViewport.Children[i];
if (mv.Content is DirectionalLight == false) currViewport.Children.Remove(mv);
}
}
The error is caught at the currViewport.Children.Count method. As previously said, the issue is that the current thread doesn't have ownership of that object. It's the first time in my multithreading experience to face with this issue. I have searched around, but couldn't find a solution.
Does anyone know how to pass the ownership of the Viewport3D-object, or a good workaround ?
Firstly, I would like to say that WPF is not a good framework for developing all but the simplest games... I would advise using a gaming framework like Microsoft's XNA instead.
However, if you insist on using WPF, then I would like to bring the CompositionTarget.Rendering event to your attention. It basically uses the frame rate of the host computer to render regulates graphics passes, avoiding the need to use timers.
You should also take a look at the How to: Render on a Per Frame Interval Using CompositionTarget page at MSDN for more helpful information and code examples.
Also, please read this extract from the book 'WPF Control Development Unleashed: Building Advanced User Experiences':
Some readers may recognize a similarity between this approach and higher-end graphics
subsystems like DirectX. Do not mistake CompositionTarget.Rendering for a good injection
point to create a WPF-based gaming graphics engine. High-end graphics and ultrahigh
frame rates are not the goal of this particular aspect of WPF animation.
Similar to the DispatcherTimer approach, animations based on CompositionTarget.Rendering
are also not time-bound. However, these events are synced with the render thread resulting
in smoother animations than the DispatcherTimer. Also there is no need to start and
stop a timer, although you may have to detach and attach the event handler to improve
performance.
UPDATE >>>
Having discovered that this is just for a course project, I would ignore my previous comment and your code example so far. Don't try to create a new rendering system when there is one already. Instead, you should follow this approach:
Create data objects that implement the INotifyPropertyChanged interface and have X, Y, and DirectionVector (could be a Size struct) public properties.
Add a Move method (or Swim method for your Fish class) in which you update the data objects' X and Y properties dependant on the value of the DirectionVector property.
Add a ListBox control to your UI.
Create a collection property to hold your data objects, add items and bind the collection to the ListBox.ItemsSource property.
Create a DataTemplate to define what your Fish objects look like... you can use the Path class to draw them and even use a RotateTransform to rotate them (the angle can be calculated from the DirectionVector property). In the DataTemplate, you can bind the X and Y properties to the `Margin' property.
Finally, add an infinite loop (possibly with a break out option) and in that loop, iterate through the collection of data objects and call Move() on each one. This will update the data objects' positions in the ListBox.
As a general rule, the only objects that can change thread allegiance in WPF are those that derive from Freezable. (E.g., Model3D is a freezable, and so, therefore, are things like Light and GeometryModel3D.)
Elements that participate directly in the visual tree do not derive from Freezable. They derive from Visual (usually, although not always, via FrameworkElement). Consequently, visual elements are forever associated with the thread on which you created them. Freezables are usually descriptive items that tell visual tree elements what to do. For example, brushes (whether solid, gradient fill, image brush or whatever) are freezables, but to do something with a brush you need to use it as a property of some visual element (i.e. something that's not a freezable) e.g., the Fill of a Rectangle.
So Model3D falls into this category - it is a description of a 3D model, but it doesn't actually know how to render itself. You provide this description to some visual element that does know how to render the model (e.g. Viewport3D).
So it's possible to build up Model3D on a worker thread, and then pass that over to the UI thread.
However, you can only start using a freezable object from some thread other than the one on which it was created after you have frozen it by calling Freeze. This, as the name suggests, prevents further modification. Once a freezable is frozen, it is no longer associated with any particular thread, so you can use it from whatever thread you like.
The intended usage model here is:
Build something complicated on a worker thread
Freeze it
Attach it to something that knows how to render it in the UI thread
This might be appropriate if you wanted to build a complex Model3D that was going to take a long time to construct, and you didn't want to make the application unresponsive while that was happening.
However, this is not of any use if you need the model to be modifiable as time goes on. If that's what you need (and it sounds like it is) then you tend to have no choice but to create the model on the UI thread - if you create a freezable that you never actually freeze (because you need the ability to change it) then you have to create it on the same thread that will render it. When you want to update the model, you either need to ensure updates are done on the UI thread, or you could use data binding, which is able to handle change notification events on any thread, and it will marshal those to the UI thread for you.
However, I'm wondering whether you really need multithreading at all. You give the reason as
to provide a better UI control (start/stop button fe).
That's not really a reason to use a separate thread. There's nothing stopping the UI thread from performing updates to the model and also responding to UI input. You just need to make sure the code that updates the model regularly returns control to the event loop.
The only reason for using a separate thread would be if the calculations that determine what the updates to the model should be are computationally expensive. For example, if you're writing code that performs a complex and highly detailed simulation of some process, and then renders the result, it might make sense to perform the calculations on a worker thread to enable the UI to remain responsive. But even then, once those calculations are complete, you'd need to ensure that the updates you make to the model based on the results of those calculations are done on the UI thread, not the worker thread.
It may be worth considering whether you can get away with building a new model each time round. The user might not actually notice if you drop the old model and instantly replace it with a newly built model. That can enable you to build the entire model on the worker thread, because you can then freeze it. If you build a new model each time, it's safe to freeze, because any time you want to change something, you just build a new model instead of updating the old one.
Yet another variation is to have a model that consists mostly of frozen pieces, contained by some unfrozen top-level elements.
I ran into the following problem with my kiosk application:
I have a window with some thumbnails. When the user clicks on a thumbnail, another window (docview) with info is displayed and in the center a document is shown..
I would like to have the docview visible instantly and then start loading the document (the document loading takes 1-3 secs)and add it to the interface afterwards.
At the moment when I click a thumb, the interfaces freezes for a second or two, and then the docview is visible with the document already..
This is what I do:
viewgrid.Children.Add(docView); // the main window uses this grid to display the windows
viewgrid.InvalidateVisual();
viewgrid.UpdateLayout(); // at this point I would like to have the docView visible
docView.showDocument(); //and afterwards, the loading of the document should start and be also visible eventually..
I tried using the LayoutUpdated event with no success..Also putting the showDocument in a separate thread didn't help either..I also read about Application.DoEvents(), but that's deprecated and seemed bad practice anyway..
How should I resolve this?
Thanks in advance!
You need to use a BackgroundWorker object to load the document. You said you tried threading, and it didn't work, but you need to get threading to work and I recommend you use a background worker.
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker(v=vs.110).aspx
I am not sure what type of document you are loading, but I loaded a RichText file using Binding as described here:
http://www.rhyous.com/2011/08/01/loading-a-richtextbox-from-an-rtf-file-using-binding-or-a-richtextfile-control/
You would do the same thing only you load the document in a BackgroundWorker. Once the document is loaded, you update the bound property and the UI will update.
You can try to use async bindings. Or do it manually with another thread and Dispatcher. But it depends on that your ShowDocument is doing and that is slow.
I got a problem with form.Show() in C# .NET Framework 2.0.
//segment code (FormA's caller)
FormA frmA = new FormA();
writeLog("Begin: " + Environment.TickCount);
frmA.SuspendLayout();
frmA.Show();
frmA.ResumeLayout();
writeLog("End: " + Environment.TickCount);
....
//segment code (FormA)
private void FormA_Load(object sender, EventArgs e){
writeLog("Begin - Load: " + Environment.TickCount);
}
From above segment code, I build in release mode and execute it.
I found diffrent time between "Begin:" and "Begin - Load" about 2 - 3 second on my notebook (Windows XP x86), yet different time on Server (Windows 2003 SP2) is more than 5 second.
I don't know why.
In addition, FormA have many TableLayout and UserControl (total controls approximate 800 )
If you've profiled and optimized your form, you might have to use a wait cursor, a splash screen or a progress bar.
If you have NOT profiled, I strongly recommend you do so. There may be a few methods that eat up a lot of time.
If you have a lot of controls (800 you say?) in your form, you might consider modifying the form's initialization to use a backgroundworker - essentially you load your controls in a separate thread. This may or may not be possible, given your specific requirements.
Edit:
I assumed in my answer that your 800 controls were necessary - it's very likely that you can reorganize your code to load controls only when needed. If you're not immediately able to reorganize your code, profiling to find the worst culprits is a good second choice.
Profile your initialize component method. Do you have non native controls? Third party ones? Some of them are notoriously slow to render. Are you setting the datasource for any of the controls? Populating a control with items at design time? Try to move them after your page load.
And yes, 800 controls is a page. That's just a badly designed page. Fix that first.
I think profiling the form might not be what you need, but rather profiling the user controls.
Or even better. If you have tabs in you form, maybe you can move the loading of controls to when a tab is fiven the focus for the first time. Only load tose cotrols that will be visible to the user on startup, then load the rest on request.