使用dataTemplateSelector为基于枚举值的视图模型选择正确的数据模板有一点问题。
这是一个重现问题的演示。
我有一个由我的viewModels
使用的模型层次结构定义模型类型的枚举是:
public enum ModelType
{
ModelA,
ModelB
}
模型基类是:
public abstract class ModelBase
{
protected ModelBase(ModelType modelType)
{
ModelType = modelType;
}
public ModelType ModelType { get; private set; }
public string Name { get; set; }
}
并且儿童模型分支是:
public class ModelA:ModelBase
{
public ModelA():base(ModelType.ModelA)
{
Name = "ModelA";
}
public string PropertyModelA { get { return "PropertyModelA"; } }
}
和
public class ModelB : ModelBase
{
public ModelB()
: base(ModelType.ModelB)
{
Name = "ModelB";
}
public string PropertyModelB { get { return "PropertyModelB"; } }
}
我的MainViewModel和ModelViewModel分别是:
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()));
}
和
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");
}
}
}
}
之后我在MainView中有一个列表框,它使用项目模板来显示每个项目。
<ListBox x:Name="entryList" ItemsSource="{Binding Models}" >
<ListBox.ItemTemplate>
<DataTemplate>
<views:ModelView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
此项目模板使用名为ModelView的其他视图来渲染item.ModelView显示公共信息,特定模型数据由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>
目前,模型选择器可以选择的视图是A和B:
<StackPanel>
<TextBlock Text="{Binding Model.PropertyModelA}" />
</StackPanel>
<StackPanel>
<TextBlock Text="{Binding Model.PropertyModelB}" />
</StackPanel>
模型选择器是:
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;
}
}
问题是DataTemplateSelector中的参数项为null,而另一个参数(Container)的dataContext为null。我无法知道ModelViewModel的值是选择正确的视图。< / p>
如果我将数据模板放在ListView项模板中,那么该项具有ModelViewMode的值,但我需要将该模板放在一个单独的文件中,因为它将用于应用程序的不同部分。
我不知道我可以访问ModelSelector中的ModelViewModel吗?
答案 0 :(得分:10)
是的,您可以通过 DataTemplateSelector 访问ViewModel。你的错误是你设置DataContext
属性:
DataContext="{Binding}"
对于 ContentPresenter ,您应该设置Content
属性
Content="{Binding}"
如果你这样做,覆盖方法中的对象item
将是Content
属性。
根据msdn article:
如果设置了ContentPresenter上的ContentTemplateSelector属性,则ContentPresenter会将相应的DataTemplate应用于Content属性,并显示生成的UIElement及其子元素(如果有)。
注意 ContentPresenter 逻辑以显示Content
。
答案 1 :(得分:3)
呃 - 在完全相同的问题上我的头撞墙后,我终于找到了问题所在。
您需要使用&#39; ContentControl&#39;而不是“内容面板”,而Stukselbax建议你需要绑定的内容,而不是datacontext。
对不起,对你来说已经太晚了2年,但希望它会帮助别人!
答案 2 :(得分:1)
迟到的答案,但要使用TemplateSelector,您需要先设置内容,因此对于ContentControl,您可以在Xaml中的ContentTemplateSelector之前设置Content ..
ListView与ItemsSource和ItemTemplateSelector相同我想。
这样的事情:
#Fails
IFS='=' read -ra myarray -d '' <"$var"
echo ${array[0]} ${array[1]]}
#Fails
echo "$var" | IFS='=' read -a array
echo ${array[0]} ${array[1]]}
#fails
echo "a=b" | IFS='=' read -a array
declare -p array
echo ${array[0]} ${array[1]}
答案 3 :(得分:0)
只是为了历史 绑定很复杂。他们打了好多次电话。在应用模板之前和之后。在我的情况下,第一次调用是在我的模板在 item 中应用 null 之前,然后在数据中应用。如此简单的答案是检查\调试项目中是否为非空。