问题描述
我有一个 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} },即DataContext
和ItemTemplate
。不是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>