Well a have a little problem using a dataTemplateSelector to choose the right datatemplate for my view model based in an enum value.
This is a demo that reproduces the issue.
I have a hierarchy of models that are used by my viewModels
The enum that define the model types is:
public enum ModelType
{
ModelA,
ModelB
}
The model base class is:
public abstract class ModelBase
{
protected ModelBase(ModelType modelType)
{
ModelType = modelType;
}
public ModelType ModelType { get; private set; }
public string Name { get; set; }
}
and the child model clases are:
public class ModelA:ModelBase
{
public ModelA():base(ModelType.ModelA)
{
Name = "ModelA";
}
public string PropertyModelA { get { return "PropertyModelA"; } }
}
and
public class ModelB : ModelBase
{
public ModelB()
: base(ModelType.ModelB)
{
Name = "ModelB";
}
public string PropertyModelB { get { return "PropertyModelB"; } }
}
My MainViewModel and the ModelViewModel respectively are:
public class MainWindowViewModel:ViewModelBase
{
public MainWindowViewModel()
{
Models = new ObservableCollection<ModelViewModel>();
LoadModels();
}
public ObservableCollection<ModelViewModel> Models { get; private set; }
private void LoadModels()
{
Models.Add(new ModelViewModel(new ModelA()));
Models.Add(new ModelViewModel(new ModelB()));
Models.Add(new ModelViewModel(new ModelB()));
}
and
public class ModelViewModel : ViewModelBase
{
private ModelBase _model;
public ModelViewModel(ModelBase model)
{
_model = model;
}
public ModelBase Model
{
get { return _model; }
set
{
if (!_model.Equals(value))
{
_model = value;
OnPropertyChanged("Model");
}
}
}
}
After that I have a List box in my MainView that use a item template to show each item.
<ListBox x:Name="entryList" ItemsSource="{Binding Models}" >
<ListBox.ItemTemplate>
<DataTemplate>
<views:ModelView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
This item template use other view called ModelView to render the item.ModelView shows the common information , the specific model data are showed by the view selected by the ModelSelector.
<UserControl.Resources>
<ResourceDictionary>
<selectors:ModelSelector x:Key="modelSelector" />
</ResourceDictionary>
</UserControl.Resources>
<StackPanel>
<TextBlock Text="{Binding Model.Name}" />
<ContentPresenter ContentTemplateSelector="{StaticResource modelSelector}" DataContext="{Binding }" />
</StackPanel>
At the moment the views that could be selected by the model selector are A and B:
<StackPanel>
<TextBlock Text="{Binding Model.PropertyModelA}" />
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding Model.PropertyModelB}" />
</StackPanel>
The model Selector is:
public class ModelSelector:DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var viewModel = item as ModelViewModel;
var dataTemplate = default(DataTemplate);
if (viewModel != null)
{
switch (viewModel.Model.ModelType)
{
case NestedDataTemplateSelectorTest.Models.ModelType.ModelA:
dataTemplate = CreateDataTemplate<ModelAView>();
break;
case NestedDataTemplateSelectorTest.Models.ModelType.ModelB:
dataTemplate = CreateDataTemplate<ModelBView>();
break;
default:
dataTemplate = this.SelectTemplate(item, container);
break;
}
}
return dataTemplate;
}
private DataTemplate CreateDataTemplate<TView>()
{
var dataTemplate = new DataTemplate();
var frameworkElement = new FrameworkElementFactory(typeof(TView));
dataTemplate.VisualTree = frameworkElement;
return dataTemplate;
}
}
The problem is that the parameter item in the DataTemplateSelector is null and the other parameter(Container) have the dataContext in null.I don't have way to know which is the value of the ModelViewModel to choose the right view.
if I put the data template in the ListView Item template then the item have the value of the ModelViewMode but I need to have that template in a separate file because it will be used in diferent parts of the application.
I dont know can i do to have access to the ModelViewModel in the ModelSelector?