I'm trying to choose the best way to implement this UI in MVVM manner. I'm new to WPF (like 2 month's) but I have huge WinForms experience.
The ListBox here act's like a TabControl (so it switches the view to the right), and contains basically the Type of item's displayed in tables. All UI is dynamic (ListBox items, TabItems and Columns are determined during run-time). The application is targeting WPF and Silverlight.
Classes we need for ViewModel:
public abstract class ViewModel : INotifyPropertyChanged {}
public abstract class ContainerViewModel : ViewModel
{
public IList<ViewModel> Workspaces {get;set;}
public ViewModel ActiveWorkspace {get;set;}
}
public class ListViewModel<TItem> where TItem : class
{
public IList<TItem> ItemList { get; set; }
public TItem ActiveItem { get; set; }
public IList<TItem> SelectedItems { get; set; }
}
public class TableViewModel<TItem> : ListViewModel<TItem> where TItem : class
{
public Ilist<ColumnDescription> ColumnList { get; set; }
}
Now the question is how to wire this to View.
There are 2 base approaches I can see here:
- With XAML: due to lack of Generics support in XAML, I will lose strong typing.
- Without XAML: I can reuse same
ListView<T> : UserControl.
Next, how to wire data, I see 3 methods here (with XAML or without doesn't matter here). As there is no simple DataBinding to DataGrid's Columns or TabControl's TabItems the methods I see, are:
- Use DataBinding with IValueConverter: I think this will not work with WPF|Silverlight out of the box control's, as some properties I need are read-only or unbindable in duplex way. (I'm not sure about this, but I feel like it will not work).
Use manual logic by subscribing to INotifyPropertyChanged in View: ViewModel.PropertyChanged+= ....ViewModel.ColumnList.CollectionChanged+= ....
Use custom controll's that support this binding: Code by myself or find 3d party controls that support this binding's (I don't like this option, my WPF skill is too low to code this myself, and I doubt I will find free controls)
Update: 28.02.2011 Things get worser and worser, I decided to use TreeView instead of ListBox, and it was a nightmare. As you probably guess TreeView.SelectedItems is a readonly property so no data binding for it. Ummm all right, let's do it the old way and subscribe to event's to sync view with viewmodel. At this point a suddenly discovered that DisplayMemberPath does nothing for TreeView (ummmm all right let's make it old way ToString()). Then in View's method I try to sync ViewModel.SelectedItem with TreeView's:
private void UpdateTreeViewSelectedItem()
{
//uiCategorySelector.SelectedItem = ReadOnly....
//((TreeViewItem) uiCategorySelector.Items[uiCategorySelector.Items.IndexOf(Model.ActiveCategory)]).IsSelected = true;
// Will not work Items's are not TreeViewItem but Category object......
//((TreeViewItem) uiCategorySelector.ItemContainerGenerator.ContainerFromItem(Model.ActiveCategory)).IsSelected = true;
//Doesn't work too.... NULL // Changind DataContext=Model and Model = new MainViewModel line order doesn't matter.
//Allright.. figure this out later...
}
And none of methods I was able to think of worked....
And here is the link to my sample project demonstrating Control Library Hell with MVVM: http://cid-b73623db14413608.office.live.com/self.aspx/.Public/MVVMDemo.zip