我通过指定HierarchicalDataTemplates并绑定到层次模型来填充TreeView。在大多数情况下,我用作不同模板中指定的ItemsSources的属性直接存在于相应的模型对象上。但是,我也想绑定到与模型对象“相关”但存储在外部的数据:在字典中,键是我的模型对象,值是此“相关”数据。我将数据存储在分层模型之外的原因是,该模型(称为“旧版”模型)是在单独的库中定义的,并且其他数据仅在我的应用程序中才会出现。我认为最干净的方法是通过定义继承或包含原始模型的新类来扩展模型,但是对于这种分层对象结构,这意味着我必须复制该结构并使它与我的对象保持同步旧模型,这是我要避免的事情。
在寻找解决方案时,我想知道是否存在扩展属性之类的东西-似乎还没有。但是我发现Henrik Jonsson的这篇文章:https://www.codeproject.com/Articles/722857/Extension-Properties,其中他展示了使用ConditionalWeakTable和ValueConverter的一种解决方法。使用他的扩展属性实现,我大多数时候都能完成我想要的事情,但是看起来仍然有些摇摇欲坠和麻烦。
在这种情况下,无法使用带有FindAncestor的RelativeSource,因为我仍然需要特定的模型对象作为数据上下文来检索相关数据。
示例模型:
public class ModelLevelA //: INotifyPropertyChanged
{
public string NameA { get; set; }
ObservableCollection<ModelLevelB> LevelB { get; set; } = new ObservableCollection<ModelLevelB>();
public ModelLevelA(string name)
{
NameA = name;
}
}
public class ModelLevelB //: INotifyPropertyChanged
{
public string NameB { get; set; }
ObservableCollection<ModelLevelC> LevelC { get; set; } = new ObservableCollection<ModelLevelC>();
public ModelLevelB(string name)
{
NameB = name;
}
}
public class ModelLevelC //: INotifyPropertyChanged
{
public string NameC { get; set; }
public ModelLevelC(string name)
{
NameC = name;
}
}
示例窗口:
public partial class MainWindow : Window
{
public Dictionary<ModelLevelC, string> ModelPropertyExtension { get; set; } = new Dictionary<ModelLevelC, string>();
public ObservableCollection<ModelLevelA> HierarchicalModel { get; set; } = new ObservableCollection<ModelLevelA>();
public MainWindow()
{
InitializeComponent();
MyModelTreeView.ItemsSource = HierarchicalModel;
PopulateModel();
LoadRelatedData();
}
private void PopulateModel()
{
// Some operation that populates the HierarchicalModel, e. g. by loading from a file.
}
private void LoadRelatedData()
{
// Some operation that loads additional data related to the objects within the HierarchicalModel and stores it in ModelPropertyExtension.
}
}
该窗口的XAML中的TreeView带有注释,我想在其中进行特殊绑定:
<TreeView x:Name="MyModelTreeView">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:ModelLevelA}" ItemsSource="{Binding Path=LevelB}">
<TextBlock Text="{Binding Path=NameA}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:ModelLevelB}" ItemsSource="{Binding Path=LevelC}">
<TextBlock Text="{Binding Path=NameB}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:ModelLevelC}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=NameC}"/>
<!--This is where I would want to bind to
ModelPropertyExtension[datacontext of this TreeViewItem]
I know that in this example there would be an exception if
the ModelObject wasn't a key of the dictionary ModelPropertyExtension-->
<TextBlock Text="{Binding }" Margin="10,0,0,0"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
总结我的问题:除了让ValueConverters参与之外,还有其他解决方案吗?