.Net Framework provides us with a new class called Lazy<T> which is used to initialize the object in lazy pace. It includes the ability to initialize the value types and to use null values. Using this class, we could implement complex navigation related applications very effectively with less memory use. For instance, consider the situation like I have a property which holds array of user controls(Approx 50 User Controls) in Silverlight application. In this instance, need to display five user controls in main page, but need to initiate all these fifty user controls to get the actual references while application load since I need to bind some elements between user controls. At the same time, rest of the user controls will be displayed when user navigate explicitly.
If we implement such a application using typical .Net property declaration/initialization without using the Lazy class, all the user control will be initialized when we use new keyword while adding items in my array property. Below is the typical .Net initialization.
// Property declaration private UserControl[] loadMyUserControl; public UserControl[] LoadMyUserControl { get { return loadMyUserControl; } set { loadMyUserControl = value; } }
// Initializing property. public MainPage() {
InitializeComponent(); var userControls = new UserControl[] { new UserControl1(), new UserControl2(), new UserControl3() }; }
In this approach, my application consumes unnecessary memory(Nearly 45 user control memory) when user open my application and closes without navigating into other pages.
But Lazy initialization occurs the first time the Lazy<T>.Value property is accessed or the Lazy<T>.ToString method is called. For my scenario, five user controls instance and memory only created while loading my application. Rest of the user controls will be created when user navigate to the corresponding page through navigation link from my main page. Below is the code snippet for lazy load.
// Property declaration private Lazy<UserControl>[] loadMyUserControl; public Lazy<UserControl>[] LoadMyUserControl { get { return loadMyUserControl; } set { loadMyUserControl = value; } }
// Initializing property. public MainPage() { InitializeComponent(); LoadMyUserControl = new Lazy<UserControl>[] { new Lazy<UserControl>(() => {return new UserControl1(); }), new Lazy<UserControl>(() => {return new UserControl2(); }), new Lazy<UserControl>(() => {return new UserControl3(); }) }; }
Now I am going to load my user controls based on navigation at runtime as below mentioned.
// Loading my fifth user control on button click private void Button_Click_1(object sender, RoutedEventArgs e) { if (!TopPanel.Children.Contains(LoadMyUserControl[5].Value)) TopPanel.Children.Add(LoadMyUserControl[5].Value); }
Note : TopPanel is the stack panel which is in main page of the application. See the demo sample for more idea.
Run the demo app and click “Status” button. Check the status of user controls. Still all the user controls are not loaded as shown in below mentioned snap.
Click “Load UserControl1” button and check the status. Now you could see, first user control loaded in view and status has been changed as True. What a great feature in framework4.0. :)
You can refer this in msdn documentation for more idea about Lazy class.
Here is the simple real time Silverlight sample which illustrates the same.
Microsoft Silverlight provides a BitmapImage class, which supports a set of features for Image expression including some of the useful events such as DownloadProgress, ImageFailed and ImageOpened events. These events can be effectively used to have a UI with nice look and feel by displaying download progress in case the images are downloaded from the web dynamically.
Probably, some folks might already have solution for this scenario. But I hope many developers don’t think in the same way. So, have got something to share on this based on my experience. My approach involves simple SpinAnimation custom control implementation. Also there are chances that my solution may not be offering something of the expertise level but at least it can help to discover the approach :).
This post explores a number of concepts; first, it involves creating tiny custom SpinAnimation control with animation, next, implementing a View Model (To follow MVVM pattern) with necessary properties for indicating progress details to the View and finally, creatingView to design the UI with Model property binding.
SpinAnimationControl - Custom Silverlight control
As there are more articles on how to create custom control in Silverlight, I am directly jumping on to the main code that is related to changing the visibility of the control based on download progress value. I know, you are asking now, why SpinAnimation control? J Can’t we change the visibility of the SpinAnimation Control based on model property value? Yes, we can change, but I want to do some operation when the visibility of animation element gets changed. Like stop and start the animation when element visibility value gets changed. Both WPF and SL do not provide the Visibility property changed callback by default. But you could achieve using property metadata override logic in WPF. Unfortunately Silverlight doesn’t have feature to override the property metadata like WPF does.So we can go ahead with generic solution which works both in SL and WPF. Let's start with SpinAnimation control constructor, which is pretty basic:
Creating dependency property called Progress which receives the download progress value from application side. Note that I have mentioned property value changed callback OnProgressChanged in PropertyMetadata. In this call back, if new value is less then 100, I am assuming that image is still not downloaded. If value is equal to 100, image gets downloaded witout any issue. So, I can change the visibility of my SpinAnimation control based on the new value. And also I can stop and start the animation after I change the visibility. Please refer the property value changed callback method for more details below.
Override OnApplyTemplate method for getting template child which has animation storyboard in resource section of root element. You can get template child using GetTemplateChild method. Grid is the root element in control template.
Here is the template of SpinAnimation control. I put some ellipses with storyboard for animating download progress indicator. Please refer the generic.xaml for complete template code.
Creating ViewModel and View to present the Image with download indicator.
If you are a SL or WPF developer, I believe that you prefer MVVM approach only, nevertheless I always prefer MVVM since it is the only powerful pattern for SL or WPF apps till now. So that is the reason I decided that implementing image Uri and Progress notification from View Model.
ImageAppViewModel class
ImageAppViewModel class has property called ImageList with the type of ObservableCollection. This is the property that we are going to bind as an ItemsSource of Listbox control in View.
public ImageAppViewModel()
{
ImagesList = newObservableCollection<ImageExt>();
ImagesList.Add(newImageExt() { Uri = "http://www.pdssb.com.my/images/stories/gallery/car.jpg" });
ImagesList.Add(newImageExt() { Uri = "http://joshua.maruskadesign.com/blog/uploaded_images/Car-02-723748.png" });
ImagesList.Add(newImageExt() { Uri = "http://www.carbodydesign.com/archive/2009/02/13-automotive-designers-show-program/Autodesk-Concept-Car-rendering-lg.jpg" });
ImagesList.Add(newImageExt() { Uri = "http://www2.hiren.info/desktopwallpapers/other/car-silver-87c.jpg" });
ImagesList.Add(newImageExt() { Uri = "http://brianhansford.com/wp-content/uploads/2010/02/red-sports-car.jpg" });
ImageExt class has property called Uri, ImageSource(Type ofBitmapImage) and Progress property. Why two property for image source in view model?. Typically we will send Image uri as a string type. See the below
But we need to construct the BitmapImage object using this uri and register the DownloadProgress event in property getter. In Download progress event handler, update the Progress property of ImageExt class which we are using for indicating how much percentage of bytes has been downloaded for particular image. Now bind only ImageSource property in ItemTemplate of ListBox in View.
Now, create the ImageAppView.xaml and put the simple list box control with ViewModel property binding. See the below code snippet, ListBox ItemsSource property bound with ImageList property which we declared in ViewModel.
Set the ItemTemplate to host our SpinAnimation and Image control to display the actual image once gets downloaded. And also I put some textboxes to show the download percentage details as well.