Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/http/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# ItemsControl、ItemContainerStyle和ItemTemplate_C#_Wpf - Fatal编程技术网

C# ItemsControl、ItemContainerStyle和ItemTemplate

C# ItemsControl、ItemContainerStyle和ItemTemplate,c#,wpf,C#,Wpf,由于我仍在努力理解ItemContainerStyle是如何工作的,所以我尝试转到定义其行为的根组件,即ItemsControl。 我能想到的最简单的样式应用就是尝试应用一些设置,比如说背景和前景 <Window.DataContext> <local:VM></local:VM> </Window.DataContext> <DockPanel > <ItemsControl ItemsSource="

由于我仍在努力理解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");
    }
}
公共类虚拟机
{
公共ObservableCollection项{get;set;}=new ObservableCollection();
公共虚拟机()
{
项目。添加(“第一”);
项目。添加(“第二项”);
项目。添加(“第三项”);
}
}
结果是:

好的,没有应用背景,但这不是我想要检查的,顺便说一句,在WPF中,似乎有比规则更多的异常。(顺便说一句,我已经尝试过为一个列表框选择的项目分配背景,这需要重新设置整个项目的模板,也许在这里是类似的?如果你知道答案,我会很感激,但我暂时不做了,因为这会让我偏离正轨)

我们还来看看可视化树:

也就是说,对于ItemsControl,项不获取“包装器元素”;如果我们对ListBox执行相同的操作,那么对于集合的每个项,它都将被构造为ListBoxItem

现在,让我们通过添加以下内容(就在
之后)来尝试为该项设置模板:


这是结果(由于MaxWidth=“100”;我想看看后面是否有东西,所以它们在中心移动):

不再应用该样式。让我们看看Viusal树:

这个可视化树并不奇怪,我们只是替换了以前是文本块的默认表示。在它的位置上,现在我们可以找到一个带有自己标准子树的标签。
令人惊讶的是,至少前景应该也适用于标签,但不幸的是,它没有

那是怎么回事? 我在这里读到了一个非常类似的问题: 与此不同的是,它尝试分配ContentTemplate。由于我仍在与这里的基本行为作斗争(我不理解那里的答案,只是有一些复制问题),我决定提出这个更基本的问题。
然而,这里似乎有一个风格定位问题,而不是复制问题;这是因为如果我保留ItemTemplate,但用TextBlock替换标签(这将导致与非模板版本完全相同的VisualTree),我将恢复前景色红色

<ItemsControl.ItemTemplate>
    <ItemContainerTemplate>
        <TextBlock MaxWidth="100" Text="{Binding}"/>
    </ItemContainerTemplate>
</ItemsControl.ItemTemplate>

变暖了? 因此,框架似乎会检查组件是否为TextBlock,如果不是,则不会应用样式。 但这是应用隐式样式时的默认行为:带有(TargetType==正在设置样式的控件类型)的stile。
在这种情况下,框架似乎假设TargetType是TextBlock,即使设置了ItemTemplate,也不会重新考虑这个假设

为了更好地理解这里的样式目标是如何工作的,我尝试显式地设置样式的TargetType,who knwos,因此让我们尝试以下方法:

<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的子类的行为似乎更合理:它为项目的容器设置样式;此处不存在该项目的容器。这只是我的猜测,因为我找不到任何说明这一点的文档。

在设置ItemContainerStyle时,您正在查看项目并考虑它们

当然,这是他们的容器,你要在上面设置样式。每个物品的容器。你并不真正关心你的容器,因为它没什么用处

也许一个用例的具体例子比理论更清晰

如果你看:

这些红色和蓝色的矩形是游戏中的单位

这些是北约的各种符号,表示步兵、炮兵骑兵等

itemcontainerstyle用于定位它们

左侧的整个面板有一个itemscontrol,其画布作为itemspanel(而不是默认的stackpanel)

每个单元都有一个viewmodel,其中一个集合绑定到该itemscontrol的itemssource

unit viewmodel有一个X和Y属性,用于在画布中定位单元

单元的位置由一个点定义,该点是其视图的中心。我想这很有趣,因为单元的viewmodel不需要计算从中心到左上角的偏移量。这由视图中的转换器完成,并使用样式应用:

<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>


在地图编辑器的其他地方,树的位置与此类似。

在设置ItemContainerStyle时,您正在查看项目并考虑它们

当然,这是他们的容器,你要在上面设置样式。每个物品的容器。你并不真正关心你的容器,因为它没什么用处

也许一个用例的具体例子比理论更清晰

如果你看到
<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>
protected virtual DependencyObject GetContainerForItemOverride()
{
    return new ContentPresenter();
}
protected override DependencyObject GetContainerForItemOverride()
{
    return new ListBoxItem();
}