Я хочу получить корневой элемент внутри приложенного DataTemplate
. Я попробовал Это но у меня это не работает, потому что для ContentPresenter
, возвращаемого MyItemsControl.ItemContainerGenerator.ContainerFromItem(vm)
, где vm
- это ViewModel, ContentPresenter.ContentTemplate
- это null
, хотя ContentPresenter.Content
- соответствующие данные (та же ViewModel).
Я бы получил доступ к DataTemplate
S в качестве ресурсов, таких как ресурсы, такие как Здесь но я не могу дать клавиши ресурсов DataTemplate
s, потому что я хочу, чтобы они были автоматически применены для всех элементы внутри ItemsControl
. Поэтому я должен найти способ получить DataTemplate
из предмета внутри ItemsControl
.
Я мог бы использовать _13 _-_ 14_ для определения ресурса DataTemplate
в функции vm.GetType()
, но я хотел бы реализовать то, что я хочу, без ItemContainerGenerator
и в соответствии с шаблоном MVVM, если это возможно, и без типов жесткого кодирования.
Ниже я думаю, что уместно в коде. Я использую, например, MyAudioFileSelector
из MainWindow
для загрузки некоторых настроек из файла данных в пользовательский интерфейс, и я не уверен, как это делается с помощью MVVM.
C # из моего фактического проекта
(Я предполагаю, что в настоящее время есть только один AudioFileSelector и один ImageFileSelector, но в будущем, вероятно, у меня их будет больше.)
internal Control GetRootControlFromContentPresenter(ContentPresenter container)
{
// what to put here?
return null;
}
internal AudioFileSelector MyAudioFileSelector
{
get
{
foreach (SettingDataVM vm in MyItemsControl.ItemsSource)
{
if (vm is AudioFileSettingDataVM)
{
return (AudioFileSelector)GetRootControlFromContentPresenter(
(ContentPresenter)MyItemsControl.ItemContainerGenerator.ContainerFromItem(vm));
}
}
return null;
}
}
internal ImageFileSelector MyImageFileSelector
{
get
{
foreach (SettingDataVM vm in MyItemsControl.ItemsSource)
{
if (vm is ImageFileSettingDataVM)
{
return (ImageFileSelector)GetRootControlFromContentPresenter(
(ContentPresenter)MyItemsControl.ItemContainerGenerator.ContainerFromItem(vm));
}
}
return null;
}
}
Пример теста
XAML
<Window x:Class="wpf_test_6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:wpf_test_6"
mc:Ignorable="d"
Title="MainWindow" Height="202" Width="274">
<Window.Resources>
<DataTemplate DataType="{x:Type local:ViewModel1}">
<TextBlock>view model 1</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ViewModel2}">
<TextBlock>view model 2</TextBlock>
</DataTemplate>
</Window.Resources>
<Grid>
<ItemsControl x:Name="MyItemsControl" Loaded="MyItemsControl_Loaded">
</ItemsControl>
</Grid>
</Window>
C # код сзади
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MyItemsControl_Loaded(object sender, RoutedEventArgs e)
{
var oc = new ObservableCollection<ViewModelBase>();
oc.Add(new ViewModel1());
oc.Add(new ViewModel2());
MyItemsControl.ItemsSource = oc;
Dispatcher.BeginInvoke(new Action(() =>
{
var container = (ContentPresenter)MyItemsControl.ItemContainerGenerator.ContainerFromItem(oc[0]);
// here container.ContentTemplate is null
Debugger.Break();
}), System.Windows.Threading.DispatcherPriority.Loaded);
}
}
public class ViewModelBase
{
}
public class ViewModel1 : ViewModelBase
{
}
public class ViewModel2 : ViewModelBase
{
}
Еще один мой важный вопрос - здесь.
Спасибо.
Обновление 1.
- В моей реальной программе у меня есть более сложные
DataTemplate
s.TextBlock
- это просто пример. - Мне нужен
ContentTemplate
, чтобы найти для конкретного контейнера / элемента / индексаDataTemplate
, который использовался. Я использую несколькоDataTemplate
s, применяемых автоматически на основе ихDataType
.
Обновление 2.
Мне нужно DataTemplate
s для отображения в окне настроек приложения различных элементов управления в ItemsControl
, каждый с DataContext
, установленным на экземпляр подтипа ViewModel для каждого типа настройки, например CheckBoxSettingDataVM
, AudioFileSettingDataVM
и т. Д. Все наследуются от SettingDataVM
.
Обновление 3.
Я не хочу явно назначать ContentTemplate
свойство явно, я хочу получить его так, из элемента (ViewModel) я могу получить контейнер (типа ContentPresenter
) и от него я могу получить корневой элемент внутри неявного DataTemplate
для просмотраModel , который может быть AudioFileSelector
, ImageFileSelector
или другой тип. Мне нужно, чтобы свойство ContentTemplate
отличалось от свойства null
, чтобы я мог сохранить ссылку на AudioFileSelector
, на ImageFileSelector
и, возможно, на другие в будущем. Я буду использовать эти ссылки для загрузки некоторых настроек из открытого файла приложения в эти Control
.
Может быть, я делаю что-то не так, но я все еще учусь MVVM. Я думаю, что моя проблема будет решена, если бы я мог установить DataType
DataTemplate
и, даже если он имеет ключ ресурса, он все равно будет автоматически применен внутри ItemsControl
s в их объеме.
Обновление 4.
Я попытался лучше разобраться, составив эту схему, надеюсь, это поможет (я понял, что это просто сложные вещи, но это часть моего вопроса.):
DataTemplate
, который использовался для создания корневого элемента. Если вам нужна ссылка на это, вы, вероятно, делаете что-то не так. - person mm8   schedule 17.09.2019DataTemplate
? - person mm8   schedule 17.09.2019DataTemplate
S для отображения в окне настроек приложения разных элементов управления вItemsControl
, каждый сDataContext
, установленным на экземпляр подтипов ViewModel для каждого типа настройки, например,CheckBoxSettingDataVM
,AudioFileSettingDataVM
и т. Д. Все наследует отSettingDataVM
. Спасибо. - person silviubogan   schedule 17.09.2019x:Key
, будут разрешены автоматически при условии, что они входят в область действия. Нет причин назначатьContentTemplate
свойство явно. - person mm8   schedule 17.09.2019