Wpf/sl:lazy Loading TreeView

Source: Internet
Author: User

Posted on January, from Matthieu Mezil

01/26/2012:code Update

Imagine the following scenario:you has a WCF service with both methods:

List<customer> GetCustomers (); list<order> getorders (int CustomerId);

You want a the TreeView with the lazy loading in a WPF Window.

There is many-to-do it.

I identify three main in my searches:

    • You can use the event on your TreeView implemented in Code-behind
    • You can makes your TreeView control inheriting the framework one ' s
    • You can use all the logic on ViewModels and use binding

The last point was realized by adding a Customerviewmodel, have a collection of Customerviewmodel in the VMS that Encapsul Ated a Customer and adding isexpanded property and add the logic of loading orders.

It's a-a-often saw in the web and that seems a good the-and-MVVM for many developers but I think, IMHO, it's not a goo D-it.

Indeed, what happens if under Orders, I want OrderDetails? You'll add a new Orderviewmodel class that encapsulates an Order and the Customerviewmodel class would have a collection of Orderviewmodel?

I don ' t want to make again my Model in my ViewModel.

I could use the ICustomTypeDescriptor (Icustomtypeprovider in SL) as I do here and I think that if this solution is inter Esting to add business logic on entity, it's not to add control logic.

I think that the lazy loading control logic should is encapsulated in a behavior and the ViewModel should just has the LA Zy loading WCF calls logic.

So, I use an Ilazyloader interface:

public interface Ilazyloader
{

String Getchildpropertyname (object obj);

    BOOL IsLoaded (object obj);
void Load (object obj);

}

and an implementation of it using delegate:

public class Lazyloader:ilazyloader
{
Private Func<object, string> _getchildpropertyname;
Private Func<object, bool> _isloaded;
Private action<object> _load;
Public Lazyloader (Func<object, string> getchildpropertyname, Func<object, bool> isLoaded, Action< object> load)
{
_getchildpropertyname = Getchildpropertyname;
_isloaded = isLoaded;
_load = load;
}
public string Getchildpropertyname (object obj)
{
return _getchildpropertyname (obj);
}
public bool IsLoaded (object obj)
{
return _isloaded (obj);
}
public void Load (object obj)
{
_load (obj);
}

}

Then, in my ViewModel, I use the following code:

public class Customerviewmodel
{
Private observablecollection<customer> _customers;
Public observablecollection<customer> Customers
{
Get
{
if (_customers = = null)
{
_customers = new observablecollection<customer> ();
var customersservice = new Customerserviceclient ();
Eventhandler<getcustomerscompletedeventargs> servicegetcustomerscompleted = null;
servicegetcustomerscompleted = (sender, e) = =
{
customersservice.getcustomerscompleted-= servicegetcustomerscompleted;
foreach (var ht in E.result)
_customers. ADD (HT);
};
customersservice.getcustomerscompleted + = servicegetcustomerscompleted;
Customersservice.getcustomersasync ();
}
return _customers;
}
}
Private Ilazyloader _lazyloader;
Public Ilazyloader Lazyloader
{
{
if (obj is Hardwaretype)
Return Propertyname.getpropertyname ((Expression<func
return null;
}, obj = _loadedhardwaretypes.contains ((hardwaretype) obj), obj = Loadhardwares ((hardwaretype) obj)); }

}

Private list<customer> _loadedcustomers = new list<customer> ();
private void LoadOrders (Customer c)
{
var customerservice = new Customerserviceclient ();
C.orders.clear ();
Eventhandler<getorderscompletedeventargs> servicegetorderscompleted = null;
servicegetorderscompleted = (sender, e) = =
{
customerservice.getorderscompleted-= servicegetorderscompleted;
foreach (Var o in E.result)
C.orders.add (o);
_loadedcustomers.add (c);
};
customerservice.getorderscompleted + = servicegetcustomerscompleted;
Customerservice.getordersasync (c.id);
}

}

Now, this is the code of my behavior:

public static Class Lazyloadtreeviewitembehavior
{
public static Ilazyloader Getlazyloader (DependencyObject obj)
{
Return (Ilazyloader) obj. GetValue (Lazyloaderproperty);
}
public static void Setlazyloader (DependencyObject obj, Ilazyloader value)
{
Obj. SetValue (lazyloaderproperty, value);
}
public static readonly DependencyProperty Lazyloaderproperty =
Dependencyproperty.registerattached ("Lazyloader", typeof (Ilazyloader), typeof (Lazyloadtreeviewitembehavior), new PropertyMetadata (applyinglazyloadinglogic));
private static void Applyinglazyloadinglogic (DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var TVI = o as TreeViewItem;
if (TVI = = null)
throw new InvalidOperationException ();
Ilazyloader lazyloader= Getlazyloader (o);
PropertyInfo Childrenprop;
if (Lazyloader = = null)
Return
Object itemvalue = TVi. DataContext;
String childrenpropname = Lazyloader.getchildpropertyname (Itemvalue);
if (Childrenpropname = = NULL | | (Childrenprop = Itemvalue.gettype (). GetProperty (childrenpropname)) = = null)
Return
IEnumerable children = (IEnumerable) childrenprop.getvalue (itemvalue, NULL);
Routedeventhandler tviexpanded = null;
        Routedeventhandler tviunloaded = null;
tviexpanded = (sender, e2) = =
{
TVi. Expanded-= tviexpanded;
                TVi. Unloaded-= tviunloaded;
if (!lazyloader.isloaded (Itemvalue))
{
Lazyloader.load (Itemvalue);
TVi. Items.clear ();
TVi. ItemsSource = children;
}
};
tviunloaded = (sender, e2) = =
{
TVi. Expanded-= tviexpanded;
TVi. Unloaded-= tviunloaded;
};
if (!children. GetEnumerator (). MoveNext ())
{
TVi. ItemsSource = null;
TVi. Items.Add (New TreeViewItem ());
}
TVi. Expanded + = tviexpanded;
TVi. Unloaded + = tviunloaded;

}
}

The thing very interesting with it are the fact that my behavior are not dependent of my model or my ViewModel and Can is used with other lazy loading treeviews.

To do it, I just has to apply our behavior into our TreeView, what can is done in XAML:

<treeview itemssource= "{Binding Customers}" >
<TreeView.ItemContainerStyle>
<style targettype= "{x:type TreeViewItem}" >
                    Value= "{Binding datacontext.lazyloader, Relativesource={relativesource Ancestortype=local:customerswindow}}"/>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
...
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>

</TreeView>

I really like the this. What does think about it?

Of course, I write my sample with WPF but it's still true with SL.

Hope This helps ...

This entry is posted in 13461, 7671, 8708. Bookmark the permalink.

Wpf/sl:lazy loading TreeView

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.