如何识别.xaml中不同项目的DataContext?

问题描述

我有一个 FilterUserControl Filterviewmodel 作为其DataContext。 在FilterControl.xaml中:

<Button x:Name="FilterButton">
  <Button.ContextMenu PlacementTarget="{x:Reference FilterButton}" ItemsSource="{Binding FilterConditions}" Style="{StaticResource ButtonContextMenu}">
                    <ContextMenu.ItemContainerStyle>
                        <Style targettype="MenuItem">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate>
                                        <MenuItem Command="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu,Mode=FindAncestor},Path=DataContext.ChangeFilterCondition}" 
                                              CommandParameter="{Binding}">
                                         ...

我在网络上搜索并知道

CommandParameter="{Binding}"

相同
CommandParameter="{Binding DataContext,RelativeSource={RelativeSource Self}}"

我原本以为DataContext是 Filterviewmodel ,但是在调试之后,我发现DataContext实际上是“ FilterConditions的每个项目”

我终于在这里得到了证据ItemsSource vs DataContext in binding case

现在,我想在.xaml中知道如何识别DataContext是什么?有哪些典型/常见情况?谢谢。

解决方法

itemcontrol(或事物是从itemscontrol继承的)只有一种情况。

https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.itemscontrol?view=netcore-3.1

将itemssource绑定到集合时。

会发生什么情况,即显示该集合中的每个项目。 然后,数据模板将提供您在模板中指定的任何UI的实例。

该行UI出现在您的itemscontrol项目面板中。

行UI包含该项的数据上下文。

您可以使用数据模板选择器或与数据类型关联的数据模板,以便获得不同的UI。

您可以更改显示这些内容的项目面板,即说是画布,而不是默认的堆栈面板。

但是无论您做什么,每个项目的数据上下文都是绑定到itemssource的集合中的那些项目之一。

,

长话短说:在ItemsControl中分配了ItemsSource的情况下,您可以确保 每个项目 具有不同的{{1} },即DataContextItemTemplate。不是ItemContainerStyle


ItemsPanel是绑定路径的根,除非您对其进行更改,否则它在整个XAML层次结构中都是相同的。

您可以显式更改DataContext或通过更改DataContext 拥有ItemsSource会更改每个元素的ItemsSource ,因此您不必照顾索引。

当您分配给DataContext时,情况并非如此,因为它隐式地将它们添加到Items并清除ItemCollection。使用ItemsSource类似于将项目添加到任何其他控件中。即Items的内容:

DataContext

就是这种情况:

<ItemsControl>
    <Button Content="{Binding A}"/>
</ItemsControl>

甚至:

<StackPanel>
    <Button Content="{Binding A}"/>
</StackPanel>

但是,使用<Button> <Button Content="{Binding A}"/> </Button> 意味着您要ItemsSource枚举给定的集合,获取每个元素,设置其ItemsControl并进行渲染。因此,DataContext在此处更改。


DataContext解析为当前的XAML元素,因此这两个相等:

RelativeSource Self

<... Prop="{Binding Path=Width,RelativeSource={RelativeSource Self}}"/> <... Prop="{Binding Path=Width,ElementName=name}" x:Name="name"/> 始终是绑定的根对象(DataContext{Binding}),因此这三个是相等的:

{Binding Path=.}

对象树中所有对象的默认绑定路径始终解析为同一对象(除非更改了它们)。例如如果<... Prop="{Binding Path=A}"/> <... Prop="{Binding Path=DataContext.A,RelativeSource={RelativeSource Self}}"/> <... Prop="{Binding Path=DataContext.A,ElementName=name}" x:Name="name"/> ,则grid.DataContext=A是网格对象树中所有对象的绑定根。

请注意,您可以在代码中更改DataContext(最好在视图的构造函数中),也可以“绑定” A以具有不同的作用域,从而使该视图:

DataContext

完全代表此虚拟机:

<Grid DataContext="{Binding}"> // this is redundant and points to VM
    <Grid DataContext="{Binding Child1}">
         <Button Command="{Binding Action11}"/>
         <Button Command="{Binding Action12}"/>
    </Grid>
    <Grid DataContext="{Binding Child2}">
         <Button Command="{Binding Action21}"/>
         <Button Command="{Binding Action22}"/>
    </Grid>
    <ItemsControl ItemsSource="{Binding Collection}">
         <ItemsControl.ItemTemplate>
             <DataTemplate>
                 <Button
                       DataContext="{Binding}" // this is redundant and points to an item
                       Command="{Binding ElementAction}"/>
             </DataTemplate>
         </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>