由于我仍在努力理解ItemContainerStyle的工作方式,所以我尝试转到定义其行为的根组件,即ItemsControl。
我能想到的最简单的样式应用程序是尝试应用几个设置,比方说项目的背景和前景。
<Window.DataContext>
<local:VM></local:VM>
</Window.DataContext>
<DockPanel >
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Control.Foreground" Value="red"/>
<Setter Property="Control.Background" Value="yellow"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
</Window>数据的基础类是:
public class VM
{
public ObservableCollection<string> Items { get; set; } = new ObservableCollection<string>();
public VM()
{
Items.Add("first");
Items.Add("second");
Items.Add("third");
}
}结果:

好的,背景没有应用,但是这不是我想要检查的,在WPF中,似乎有更多的例外而不是规则。( BTW2,我已经为分配ListBox所选项目的背景进行了斗争,这需要重新定位整个项目,也许这里是类似的?如果你知道答案的话,我们会很感激的,但我暂时不提了,因为它让我偏离了轨道)。
让我们看一看视觉树:

也就是说,对于ItemsControl,条目不会得到一个“包装器元素”;如果我们对一个ListBox做同样的操作,那么对于集合中的每个项,它都将被构造为一个ListBoxItem。
现在,让我们尝试通过添加以下内容(就在</ItemsControl.ItemContainerStyle>之后)来模板该项:
<ItemsControl.ItemTemplate>
<ItemContainerTemplate>
<Label MaxWidth="100" Content="{Binding}"/>
</ItemContainerTemplate>
</ItemsControl.ItemTemplate>这就是结果(由于MaxWidth=“100”,它们在中间移动;我想看看后面是否有什么东西):

这种样式不再适用了。让我们看一看葡萄树:

这个可视化树并不奇怪,我们只是替换了以前是TextBlock的默认表示形式。在它的位置,我们现在找到了一个标签与它自己的标准子树。
令人惊讶的是,至少前景应该也适用于标签,但不幸的是,它并不适用。
那是怎么回事?
我在这里读到了一个非常类似的问题:Can't use ItemTemplate and ItemContainerStyle together? --它与此不同的是,它试图分配ContentTemplate。因为我仍然在为基本的行为而挣扎(除了有某种复制问题外,我不明白答案),所以我决定提出一个更基本的问题。
然而,这里似乎存在一个样式定位问题,而不是复制问题;这是因为如果我保留ItemTemplate,但是用TextBlock替换标签(这将导致与非模板版本的VisualTree完全相同),我会得到我的前景红色!
<ItemsControl.ItemTemplate>
<ItemContainerTemplate>
<TextBlock MaxWidth="100" Text="{Binding}"/>
</ItemContainerTemplate>
</ItemsControl.ItemTemplate>变暖了?
因此,框架似乎检查组件是否为TextBlock,如果不是,则检查是否应用样式。但这是应用隐式样式时的默认行为:带有(TargetType,==,被样式化的控件的类型)。
在这种情况下,框架似乎假设TargetType是TextBlock,即使设置了ItemTemplate,也不会重新考虑这个假设。
为了更好地理解样式目标是如何工作的,我尝试显式地设置样式的TargetType,让我们尝试如下:
<ItemsControl.ItemContainerStyle>
<Style TargetType="Label">
<Setter Property="Label.Foreground" Value="red"/>
<Setter Property="Label.Background" Value="yellow"/>
</Style>
</ItemsControl.ItemContainerStyle>看到TargetType=“标签”了吗?太棒了。它给出了错误:
不能应用于ContentPresenter,一种用于标签的样式。
(翻译自意大利语,也许不是英文的确切措辞。)如果你手头有,请用确切的那个代替)。
也就是说,它期望:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Label.Foreground" Value="red"/>
<Setter Property="Label.Background" Value="yellow"/>
</Style>
</ItemsControl.ItemContainerStyle>这有点道理,因为根据前面显示的可视树,每个项的根节点实际上是ContentPresenter。
在这一点上,我很困惑:它应该如何工作?目前的想法是,它没有。像ListBox这样的子类的行为似乎更明智:它为项的容器设置样式;在这里,项的容器不存在。这只是我的猜测,因为我找不到任何这样的文件。
发布于 2020-08-14 10:34:18
您正在查看您的项目,并在设置ItemContainerStyle时考虑它们。
但当然,这是他们的容器,你正在设置一个样式。每个项目的容器。你并不在乎你的容器,因为它做的不多。
也许一个用例的具体例子会比理论更清楚。
如果你看:
https://i.imgur.com/UZ6Nqrc.png
这些红蓝长方形是这个游戏中的单位。
这些都是北约的各种标志,表示步兵、炮兵骑兵等。
项目容器样式用于对它们进行定位。
左边的整个面板都有一个带有画布的itemscontrol,因为它是itemspanel (而不是默认的堆栈面板)。
每个单元都有一个视图模型,这些元素的集合绑定到项目控件的项源。
单元视图模型具有X和Y属性,用于在该画布中定位单元。
一个单位的位置是由它的观点的中心点来定义的。我认为这很有趣,因为单元的视图模型不需要计算从中间到左上角的偏移量。这由视图中的转换器完成,并使用样式应用:
<Style TargetType="ContentPresenter" x:Key="CenteredContentPresenter">
<Setter Property="Canvas.Top">
<Setter.Value>
<MultiBinding Converter="{local:MultiAddConverter}">
<Binding Path="Y" Mode="TwoWay"/>
<Binding Path="ActualHeight"
Converter="{local:MultiplyConverter Multiplier=-.5}"
RelativeSource="{RelativeSource Self}"
Mode="TwoWay" />
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="Canvas.Left">
<Setter.Value>
<MultiBinding Converter="{local:MultiAddConverter}">
<Binding Path="X" Mode="TwoWay"/>
<Binding Path="ActualWidth"
Converter="{local:MultiplyConverter Multiplier=-.5}"
RelativeSource="{RelativeSource Self}"
Mode="TwoWay" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>在地图的其他地方,编辑器树也以类似的方式定位。
发布于 2020-08-14 11:13:04
ItemContainerStyle应用于由虚拟GetContainerForItemOverride方法创建的项容器。
在ItemsControl基类中,此方法返回一个ContentPresenter
protected virtual DependencyObject GetContainerForItemOverride()
{
return new ContentPresenter();
}在派生的ListBox类中,它返回一个ListBoxItem
protected override DependencyObject GetContainerForItemOverride()
{
return new ListBoxItem();
}TargetType的ItemContainerStyle必须匹配从这个方法返回的DependencyObject的类型。否则,当在运行时将样式应用于容器时,您将得到一个异常。
https://stackoverflow.com/questions/63410059
复制相似问题