gpt4 book ai didi

c# - 没有资源 key 时,如何在应用的DataTemplate中获取根元素?

转载 作者:行者123 更新时间:2023-12-03 10:31:47 24 4
gpt4 key购买 nike

我希望将根元素放入已应用的DataTemplate中。我尝试了this,但它对我不起作用,因为对于ContentPresenter返回的MyItemsControl.ItemContainerGenerator.ContainerFromItem(vm),其中vm是ViewModel,ContentPresenter.ContentTemplatenull,尽管ContentPresenter.Content是相应的数据(相同的ViewModel)。

我将DataTemplate s作为诸如here之类的资源来访问,但我无法提供DataTemplate的资源键,因为我希望它们能够自动应用于ItemsControl内的所有项目。因此,我必须找到一种从DataTemplate内的项目获取ItemsControl的方法。

我可以使用if-else来确定DataTemplate函数中的vm.GetType()资源,但是我想在没有ItemContainerGenerator的情况下并且根据MVVM模式(如果可能)并且在没有硬编码类型的情况下实现我想要的功能。

以下是我认为与代码相关的内容。例如,我使用MyAudioFileSelector中的MainWindow将数据文件中的某些设置加载到UI中,我不确定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
{
}

我的另一个相关问题是 here

谢谢你。

更新1
  • 在我的实际程序中,我有更复杂的DataTemplateTextBlock只是一个示例。
  • 我需要一个ContentTemplate来找到特定容器/项目/索引的所使用的DataTemplate。我使用了基于DataTemplate自动应用的多个DataType

  • 更新2

    我需要 DataTemplate在应用程序的``设置''窗口中显示 ItemsControl中的不同控件,每个控件的 DataContext设置为每种设置类型的ViewModel子类型的实例。 CheckBoxSettingDataVMAudioFileSettingDataVM等都从 SettingDataVM继承。

    更新3

    我不想显式地分配 ContentTemplate属性,我想从项目(ViewModel)中获取它,我可以获取容器(类型 ContentPresenter),并从中获取根元素,该元素位于ViewModel的隐式 DataTemplate中,可以是 AudioFileSelectorImageFileSelector或其他类型。我需要 ContentTemplate属性与 null不同,以便将来可以存储对 AudioFileSelectorImageFileSelector以及其他引用的引用。我将使用这些引用将应用程序打开的文件中的某些设置加载到这些 Control中。

    也许我做错了事,但我仍在学习MVVM。我认为,如果我可以设置 DataTypeDataTemplate,那么我的问题将得到解决,即使它具有资源 key ,它仍将自动应用于其范围内的 ItemsControl s中。

    更新4

    我试图通过制定此方案来更好地理解,希望对它有所帮助(我意识到这只是复杂的事情,但这是我的问题的一部分。):

    schema

    最佳答案

    通过执行以下操作,可以从代码隐藏中通过给定ViewModel对象的DataTemplate检索实例化ItemsControl的根可视对象:

    //Assuming you have access to a viewModel variable and to your MyItemsControl:
    //We retrieve the generated container
    var container = MyItemsControl.ItemContainerGenerator.ContainerFromItem(viewModel) as FrameworkElement;
    //We retrieve the closest ContentPresenter in the visual tree
    FrameworkElement firstContentPresenter = FindVisualSelfOrChildren<ContentPresenter>(container);
    //We get the first child which is the root of the DataTemplate
    FrameworkElement visualRoot = (FrameworkElement)VisualTreeHelper.GetChild(firstContentPresenter, 0); //this is what you want

    您需要此帮助程序功能来解析可视化树,以查找正确类型的第一个子级。

    /// <summary>
    /// Parses the visual tree down looking for the first descendant (or self if correct type) of the given type.
    /// </summary>
    /// <typeparam name="T">Type of the descendant to find in the visual tree</typeparam>
    /// <param name="child">Visual element to find descendant of</param>
    /// <returns>First visual descendant of the given type or null. Can be the passed object itself if type is correct.</returns>
    public static T FindVisualSelfOrChildren<T>(DependencyObject parent) where T : DependencyObject {
    if (parent == null) {
    //we've reached the end of the tree
    return null;
    }
    if (parent is T) {
    return parent as T;
    }
    //We get the immediate children
    IEnumerable<DependencyObject> children = Enumerable.Range(0, VisualTreeHelper.GetChildrenCount(parent)).Select(i => VisualTreeHelper.GetChild(parent, i));
    //We parse them to get the first child of correct type
    foreach (var child in children) {
    T result = FindVisualSelfOrChildren<T>(child);
    if (result != null) {
    return result as T;
    }
    }
    //Nothing found
    return null;
    }

    关于c# - 没有资源 key 时,如何在应用的DataTemplate中获取根元素?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57974279/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com