Элемент является нулевым в DataTemplateSelector
У нас есть небольшая проблема с использованием 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");
}
}
}
}
После этого у меня в главном окне есть список, в котором для отображения каждого элемента используется шаблон элемента.
<ListBox x:Name="entryList" ItemsSource="{Binding Models}" >
<ListBox.ItemTemplate>
<DataTemplate>
<views:ModelView/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Этот шаблон элемента использует другое представление, называемое ModelView, для визуализации элемента. 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>
Модель Selector это:
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 для выбора правильного представления.
если я помещаю шаблон данных в шаблон элемента ListView, тогда этот элемент имеет значение ModelViewMode, но мне нужно иметь этот шаблон в отдельном файле, поскольку он будет использоваться в разных частях приложения.
Я не знаю, я могу сделать, чтобы иметь доступ к ModelViewModel в ModelSelector?
4 ответа
Да, вы можете получить доступ к вашему ViewModel через DataTemplateSelector. Ваша ошибка в том, что вы установили DataContext
имущество:
DataContext="{Binding}"
Для ContentPresenter вы должны установить Content
свойство вместо
Content="{Binding}"
Если вы будете делать это, объект item
внутри переопределенного метода будет точно Content
имущество.
Согласно статье MSDN:
Если свойство ContentTemplateSelector в ContentPresenter установлено, ContentPresenter применяет соответствующий DataTemplate к свойству Content, и отображается результирующий UIElement и его дочерние элементы, если таковые имеются.
Обратите внимание на логику ContentPresenter для отображения Content
,
Ухх - после того, как я ударился головой о стену с точно такой же проблемой, я наконец понял проблему.
Вам нужно использовать ContentControl вместо ContentPanel, и, как предполагает Stukselbax, вам нужно связать контент, а не текстовый текст.
Извините, для вас уже 2 года, но надеюсь, это поможет кому-то еще!
Поздний ответ, но чтобы использовать TemplateSelector, вам нужно сначала установить содержимое, поэтому для ContentControl вы устанавливаете Content перед ContentTemplateSelector в Xaml.
То же самое для ListView с ItemsSource и ItemTemplateSelector, я думаю.
Что-то вроде этого:
<ContentControl Content="{Binding Animals}" ContentTemplateSelector="{StaticResource AnimalTemplateSelctor}" />
просто для истории привязки сложны. Звонят несколько раз. До применения шаблонов и после. В моей ситуации первый вызов был до того, как мои шаблоны применялись с нулевым значением в элементе, а после с данными. Таким образом, простой ответ - проверить\отладить не нуль в элементе.