I wish to get the root element inside an applied DataTemplate
. I tried this but it does not work for me, because for the ContentPresenter
returned by MyItemsControl.ItemContainerGenerator.ContainerFromItem(vm)
where vm
is a ViewModel, ContentPresenter.ContentTemplate
is null
, although ContentPresenter.Content
is the corresponding data (the same ViewModel).
I would access DataTemplate
s as resources like here but I cannot give the DataTemplate
s resource keys because I want them to be automatically applied to all the items inside the ItemsControl
. So I must find a way to get the DataTemplate
from an item inside the ItemsControl
.
I could use if
-else
for determining the DataTemplate
resource in function of the vm.GetType()
but I would like to realize what I wish without ItemContainerGenerator
and according to the MVVM pattern, if possible, and without hard-coding types.
Below is what I think is relevant in the code. I use, for example, MyAudioFileSelector
from MainWindow
to load some settings from the data file into the UI and I am not sure what is the MVVM way of doing this.
C# from my actual project
(I suppose currently that there is only one AudioFileSelector and one ImageFileSelector, but in future probably I will have more of them.)
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;
}
}
Test example
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# code-behind
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
{
}
Another relevant question of mine is here.
Thank you.
Update 1
- In my actual program I have more complex
DataTemplate
s. TheTextBlock
is just an example. - I need a
ContentTemplate
to find, for a specific container/item/index, theDataTemplate
that was used. I use multipleDataTemplate
s applied automatically based on theirDataType
.
Update 2
I need DataTemplate
s to display in a Settings window of an application different controls in an ItemsControl
, each with the DataContext
set to an instance of a ViewModel subtype for each setting type, e.g. CheckBoxSettingDataVM
, AudioFileSettingDataVM
etc. all inheriting from SettingDataVM
.
Update 3
I do not want to assign the ContentTemplate
property explicitly, I want to get it so, from an item (ViewModel) I can get the container (of type ContentPresenter
) and from it I can get the root element inside the implicit DataTemplate
for the ViewModel, which can be AudioFileSelector
, ImageFileSelector
or other type. I need the ContentTemplate
property to be different than null
so I can store a reference to the AudioFileSelector
and to the ImageFileSelector
and maybe others in the future. I will use these references to load some settings from the application's opened file into these Control
s.
Maybe I am doing something wrong, but I am still learning MVVM. I think that my problem would be solved if I could set the DataType
of the DataTemplate
and, even if it has a resource key, it would still be automatically applied inside the ItemsControl
s in their scope.
Update 4
I tried to understand better by making this scheme, I hope it helps (I realized it just complicated things, but it is part of my question.):