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

How to identify the DataContext of different items in .xaml?

我有一个 FilterUserControlFilterViewModel 作为它的 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 是什么? typical/common 个案例是什么?谢谢。

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

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

当您将 itemssource 绑定到集合时。

该集合中的每个项目都会出现。 Datatemplating 然后给出您在模板中指定的任何 UI 的实例。

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

行 UI 具有项目的数据上下文。

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

您可以更改显示这些的项目面板,例如 canvas 而不是默认的堆栈面板。

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

长话短说:在分配了 ItemsSourceItemsControl 中,您可以确定 每个项目 有一个不同的 DataContext,这意味着 ItemTemplateItemContainerStyle。不是 ItemsPanel.


DataContext 是绑定路径的根,它在整个 XAML 层次结构中保持不变,除非您更改它。

您可以明确更改 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 在那里被改变了。


RelativeSource Self 解析为当前的 XAML 元素,所以这两个是相等的:

<... 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=AA 是分层网格对象树中所有对象的绑定根。

请注意,您可以在代码中更改 DataContext(最好在视图的构造函数中),或者您可以“绑定”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>

完美代表此虚拟机:

 VM
     Child1
         Action11
         Action12
     Child2
         Action21
         Action22
     Collection
         Item1
              ElementAction
         Item2
              ElementAction
         Item3
              ElementAction
         ...