【问题标题】:How to identify the DataContext of different items in .xaml?如何识别 .xaml 中不同项目的 DataContext?
【发布时间】:2020-08-12 13:58:42
【问题描述】:

我有一个 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 是什么?有哪些典型/常见案例?谢谢。

【问题讨论】:

    标签: wpf data-binding datacontext


    【解决方案1】:

    长话短说:在分配有ItemsSourceItemsControl 中,您可以确定每个项目 都有不同的DataContext,这意味着@987654324 @ 和 ItemContainerStyle。不是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
             ...
    

    【讨论】:

      【解决方案2】:

      itemscontrol(或从 itemscontrol 继承的东西)只有一种情况。

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

      当您将 itemssource 绑定到集合时。

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

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

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

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

      您可以更改显示这些的项目面板,使其成为画布而不是默认的堆栈面板。

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

      【讨论】:

        猜你喜欢
        • 2015-02-18
        • 2020-05-04
        • 1970-01-01
        • 2017-10-28
        • 2011-05-14
        • 1970-01-01
        • 1970-01-01
        • 2010-11-03
        • 1970-01-01
        相关资源
        最近更新 更多