Advice needed on WPF TreeView and lazy load databinding with NHibernate - wpf

I'm working on a project where I need to provide some treeviews to the users. So far I've managed to get my business objects and their persistence to a database fully functional.
I'm using NHibernate with SQLite3 to store the objects. The business object is as follows:
public class ErrorObject
{
public virtual int ID { get; set; }
public virtual string Description { get; set; }
private IList<ErrorObject> _errorObjects = new List<ErrorObject>();
public virtual IList<ErrorObject> ErrorObjects
{
get { return _errorObjects; }
set { _errorObjects = value; }
}
}
I'm binding this to a treeview like this:
<TreeView ItemsSource="{Binding ErrorObjects}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type DataModel:ErrorObject}"
ItemsSource="{Binding ErrorObjects}">
<TextBlock Text="{Binding Path=Description}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
What puzzles me, is the fact that, as long as I don't close the NHibernate session, I have full lazy loading out-of-the-box :o)
Can anybody advice if this is the way to continue? Or have I a flawed concept?

Seems to be a good concept.
In NET 3.5 SP1 virtualization support has been added to TreeView (by adding support for hierarchical data to VirtualizingStackPanel).
As long as NHibernate fills the child list ErrorObjects when it was requested (first access to the getter) the tree should build up with lazy loading.

That's how it's designed to work, so just be happy about it :-)

You should make the ErrorObject implement INotifyPropertyChanged/INotifyCollectionChanged if you want the UI to be updated when the collection updates, OR make the ErrorObjects property to be of type ObservableCollection<ErrorObject>, ObservableCollection<T> implements INotifyCollectionChanged and INotifyPropertyChanged`.
I think the best idea for your scenario would be use an ObservableCollection instead of the List, if I am not wrong, the ObservableCollection<T> does implement IList<T> too.

Related

Best model for WPF+MVVM+EF 6.1

I’m trying to figure out best model for my WPF+MVVM+EF 6.1 application and I’m little confuse how to do this right after watching many EF courses and blogs. When modeling application in WPF there is a need for INotifyPropertyChanged, Observablecollection and also adding some additional calculated properties (not persisted on the database). I’m considering this solutions:
Change EF T4 template and implement INotifyPropertyChanged, change collections to Observablecollection and add additional fields in partial class. This brings to bind to EF model but looks simple and easer to maintain;
Use separate class for domain objects and rewrite data between them – for instance using automapper. This have separation of concerns but all updated and inserted entities have to be translated to appropriate EF entities.
Implement new class that have EF class nested inside new class with all properties wrapped and change tracked – this in other hand brings redundant code.
What will be best solution for this which not involve writing redundant code?
How about using the generated EF entities as it is and creating a DTO model that implements INotifyPropertyChanged only when it is necessary.
Not in every case you need to be able to synchronize the data between the view and the model right away.
Don't abuse the usage of INotifyPropertyChanged. It will be too late when you realize that you have a lot of extra code that doesn't actually need two way binding, a lot of repetitive work and can't be reused by other client view (could be an asp.net) because it's too technology specific (for example dependency property).
And the MVVM pattern works fine for a simple data display without you have to implement INotifyPropertyChanged for the binding data.
public class Order
{
public string OrderNo { get; set; }
public DateTime Date { get; set; }
}
public class WindowViewModel
{
public WindowViewModel()
{
var orders = Service<TheEntity>.Get();
Array.ForEach(orders, order => Orders.Add(order));
}
private readonly ObservableCollection<Order> _orders = new ObservableCollection<Order>();
public ObservableCollection<Order> Orders
{
get { return _orders; }
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new WindowViewModel();
}
}
<Window DataContext="{Binding RelativeSource={RelativeSource Self}}">
<ListView ItemsSource="{Binding Orders}">
<ListView.View>
<GridView>
<GridViewColumn Header="OrderNo" DisplayMemberBinding="{Binding OrderNo}"/>
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Date}"/>
</GridView>
</ListView.View>
</ListView>
</Window>
The best way is not to disturb auto-generated code from EF, even if you wrap it inside, new class, you still need some mechanism to track and save changes, doing it so completely overrides for what entity framework is designed for (less coding in DAL). The best way is to have properties (observable collection or i notify properties in VM- View Model). You might need to put little more code into your application but that helps you and to maintain the code and it will be total decoupled from other modules (BL, DAL, ..) of the application.

Removing UserControl code behind for use with MVVM

I am trying to create a user control using MVVM.
Basically I am trying to wrap a combobox that will pull data from a respository. This will allow me to use the same combobox in many different views in my application. There will be many of the wrapped comboboxes throughout the application.
I was easily able to create this control using a DependencyProperty and code-behind. I am now trying to convert this to MVVM and am having trouble figuring out how to get the value back to /from the ViewModel that in bound to the View where my combobox is located.
Any ideas or suggestions would be greatly appreciated at this point.
Thanks,
Eric
It is perfectly acceptable to use a UserControl that has code behind in it when using MVVM. If you really want to move the functionality out of the UserControl, then move it to whichever parent view models will require it. If you don't want to have the same code repeated in several places, you could encapsulate it in a class and add an instance of that class as a property to each of the relevant view models.
if you have a viewmodel that will pull data from a respository - you can use the same viewmodel in many different viewmodels in your application :)
and if you use a datatemplate your views know how to render this viewmodel
<DataTemplate DataType="{x:Type local:MyPullDataViewmodel}">
<view:MyCoolPullDataShowComboboxUserControl />
</DataTemplate>
It's pretty easy.
Let's say you have:
MyUserControlView.xaml
MYUserControlViewModel.cs
MyMainWindowView.xaml - For your MainWindow view (the one containing the UserControl)
MyMainWindowViewModel.cs - Your MainWindow ViewModel.
And you want to bind List<string> MyListToBind
And leave the code-behind completely empty.
MyUserControlViewModel.cs
public class MyUserControlViewModel
{
private List<string> _MyListToBind;
public List<string> MyListToBind { get; set;}
}
MyMainWindowViewModel.cs
public class MyUserControlViewModel
{
private MyUserControlViewModel _MyControlViewModel;
public MyUserControlViewModel MyControlViewModel { get; set;}
}
MyMainWindowView.xaml
<Window ...
xmlns:my="clr-namespace:NamespaceContainingYourUserControlView>
<my:MyUserControlView DataContext = "{Binding Path= MyControlViewModel}"/>
</Window>
MyUserControlView.xaml
<UserControl ...>
<DataGrid ItemsSource = "{Binding Path= MyListToBind}" .../>
...
</DataGrid>
</UserControl>
This doesn't support ViewModel updating View. To do that You have to use either DependencyProperties as you did instead of normal variables (as i did) or use INotifyPropertyChanged(google it, you'll get tons of examples) and OnPropertyChanged event.
You might read up on DataTemplates they are really useful in data binding.
You can find this usefeul:
http://www.youtube.com/watch?v=BClf7GZR0DQ
I sure as hell did !
Good luck.

TreeView incorrectly shows items as expanded when using VirtualizationMode.Recycling

Whenever I used TreeView I always had just few nodes and each of them usually had less than 100 items. I never really needed any kind of ui virtualization for that but now for the first time I need it.
The problem appears when using ui virtualization with recycling mode the TreeView seems to expand items even though I never expanded them manually.
I googled the issue and as far I understood recycling mode of virtualization in TreeView the containers get reused.
So I assume that the cause might be applying already expanded reused container to an item which wasn't expanded before.
Here is a simple example:
https://github.com/devhedgehog/wpf/
For those who cannot download code for whatever reason here is basically what I have tried to do with the TreeView.
This is what I have in XAML.
<Grid>
<TreeView ItemsSource="{Binding}" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingStackPanel.VirtualizationMode="Recycling">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Parts}">
<TextBlock Text="{Binding Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
And this is code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
IList<Car> list = new List<Car>();
for (int i = 0; i < 5000; i ++)
{
list.Add(new Car() { Name = "test1" + i });
}
foreach (var car in list)
{
car.Parts = new List<string>();
for (int i = 0; i < 500; i++)
{
car.Parts.Add("asdf" + i);
}
}
this.DataContext = list;
}
}
public class Car
{
public string Name
{
get;
set;
}
public List<string> Parts
{
get;
set;
}
}
I hope somebody can provide me a solution to this issue. Is this a known bug?
I am sorry in case its a duplicate. Futhermore I hope you guys tell me what I did wrong since this is my first post before you downgrade the question.
As you probably know, this problem can be solved easily by using standard recycling mode:
<TreeView VirtualizingStackPanel.VirtualizationMode="Standard" ...>
This shouldn't have too much of an impact on your TreeView's performance, as the tree will still be virtualized and a container will only be created for visible items. The benefits of the recycling mode only come into play when scrolling (when items are both being virtualized and realized), and usually the standard virtualization mode is good enough.
However, in case performance is really critical (or if you really want a solution for this while keeping the recycling mode, or if you're looking to do things the right way), you can use backing data and data binding to solve this problem.
The reason why this problem occurs in the first place is this:
Let's say you have a TreeViewItem which has its IsExpanded property set to true. When it's being recycled, i.e. its data is replaced, its IsExpanded property remains the same because it has no way to know whether it should be expanded or not, because that data is not available anywhere. The only place where it exists is the IsExpanded property of the TreeViewItem, and it's not going to be relevant because that item is being reused along with its properties.
If however you have a viewmodel for each tree item you'll be able to bind each TreeViewItem to the IsExpanded property in your TreeViewItemViewModel (you will have a view model for each tree item) and you will always get the correct value because you've made that data available and bound each item to it.
Your TreeView's ItemsSource will be bound to a collection of TreeViewItemViewModel objects, and your TreeViewItemViewModel class will look something like this:
class TreeViewItemViewModel : INotifyPropertyChanged
{
bool IsExpanded { get; set; }
bool IsSelected { get; set; }
TreeViewItemViewModel Parent { get; }
ObservableCollection<TreeViewItemViewModel> Children { get; }
}
You can find more information on how exactly to create such view model in Josh Smith's excellent article Simplifying the WPF TreeView by Using the ViewModel Pattern.

A simpel WPS using MVVM and EF

I'm on the edge of going nuts.
I have a working WinForms/database application, that I try to rebuild with WPF. My main problem is that I haven't worked with MVVM before and I can't seem to get the grip of the databinding from Entity Framework to the View.
My WinForms is build exclusively using code-behind, which I know is bad praxis, but it works.
I have read about 100 articles, tutorials and examples, downloaded a couples of demo/samples using MVVM. Including "WPF Application Framework (WAF)"
But I haven't found a simple solution/sample how to use EF as the Model or as a dataprovider for the Model. And to pass the information on to to the ViewModel, and lastly bind it from the View.
All the tutorials I have read only describe fetching data from a static list, I need the usual CRUD operations on the database.
I know questions like this are being asked all the time here, but I haven't being able to find an answer to pushing data from EF to the View(Model) and update back through EF. I hope that some of you can help a (must be retarded) person like me with some guiding.
The MVVM pattern hinges, a lot, on the INotifyPropertyChanged interface which EF implements so some of the work here is done for you.
I am not too sure on your particular requirement but start off by creating a view mode for your window. Lets assume that you have a entity called Person with an attribute of FirstName as a string and an Id of Int32 (of course), and that all the work for the data layer is taken care of. I will show you how to list the Person entity and allow edit of the person entity as well.
ViewModel
public class Window1ViewModel : INotifyPropertyChanged {
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Person> _people;
private Person _selectedPerson;
public ObservableCollection<Person> People {
get { return _people; }
set { _people = value;
this.RaisePropertyChanged("People");
}
}
public Person SelectedPerson {
get { return _selectedPerson; }
set { _selectedPerson = value;
this.RaisePropertyChanged("SelectedPerson");
}
public Window1ViewModel() {
// Instead of setting to empty collection populate with data from EF.
this.People = new ObservableCollection<Person>();
}
private void RaisePropertyChanged(string propertyName) {
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Now that you have your ViewModel taken care of it is time to create the UI and bind it.
Binding ListBox
<ListBox ItemsSource="{Binding Source={StaticResource viewModel}, Path=People}" SelectedItem="{Binding Source={StaticResource viewModel}, Path=SelectedPerson, Mode=TwoWay}"/>
Binding TextBox
<TextBox Text="{Binding Source={StaticResource viewModel}, Path=SelectedPerson.FirstName, Mode=TwoWay}"/>
Lastly you could create a button on your Window, bind it to an ICommand on your ViewModel to call the Save() method in the EF layer.
There is a lot you could write to meet your requirement i hope this goes some way to assist. Also recommend the following information. http://www.codeproject.com/Articles/81484/A-Practical-Quick-start-Tutorial-on-MVVM-in-WPF

How to update the UI using bindings

I have a DataGrid and two ListBoxes in my window. I am using Entity Framework to Connect to my SQL Server. Depending on the selections I make in the ListBoxes parameters will be passed to my stored procedure and data for my DataGrid will be retrieved. I was able to implement this functionality without using MVVM. I would like to know ways to implement this using MVVM. Please Help me out. Thanks in Advance.
First of all, MVVM is about separating the concerns of your code into the appropriate area. For example, talking to your database via EF should be done in the Model1. The ViewModel is responsible for holding the data, and for shaping or massaging it to make it more suitable for display (i.e. transforming enums to colors2, etc).
To implement your functionality in a MVVM way, you will need to use binding, and bind your viewmodel to your view:
<MyControl>
<LayoutRoot>
<ListBox ItemsSource={Binding MyItems} SelectedItem={Binding MySelection} />
</LayoutRoot>
</MyControl>
in the code behind for the View:
public class MyControl
{
public MyControl()
{
this.DataContext = new MyViewModel();
}
}
and your ViewModel will look something like this:
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<MyDataObject> MyItems
{
get { return _myItems; }
set
{
_myItems = value;
OnPropertyChanged("MyItems");
}
}
public MyDataObject MySelection { get; set; }
public void DoSomethingWithDatabase()
{
Model.DoSomething(MySelection);
}
}
This is just a VERY simple example to illustrate what is required if you do things the MVVM way (and I've deliberately missed out a bunch of stuff). To do a proper example and document all the essential bits you need to know would take at least a chapter in a book, so I'll refer you to a MSDN article for further reading: Implementing the Model-View-ViewModel Pattern.
1 And the Model may just be a stepping stone if you also implement SOA, the Model might just call a service which then talks to the database.
2 This can also be done with Converters in the View, but may not always be possible or practical in a converter.

Resources