【问题标题】:How to use Canvas as the ItemsPanel for an ItemsControl in Silverlight 3如何在 Silverlight 3 中使用 Canvas 作为 ItemsControl 的 ItemsPanel
【发布时间】:2010-03-05 00:56:30
【问题描述】:

我正在尝试使用 Silverlight 3 在 ItemsControl DataTemplate 中设置 Canvas 属性。根据this post,这样做的唯一方法是使用 ContentPresenter 类型的 ItemsContainerStyle 设置它,因为 Canvas 属性仅生效在画布的直接子代上。这似乎在 SL3 中不起作用,因为 ItemsControl 没有 ItemsContainerStyle 属性,所以我按照this article 的建议尝试了一个 ListBox,但它仍然不起作用。从下面的 XAML 中,我希望看到一个绿色正方形,数字 10、30、50、70 从“NW”到“SE”方向级联。谁能告诉我为什么他们都在西北角叠在一起?

<UserControl x:Class="TestControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib" >
    <StackPanel>
        <ListBox>
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas Background="Green" Width="100" Height="100" />
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding}" />
                </DataTemplate>                
            </ListBox.ItemTemplate>
            <ListBox.ItemContainerStyle>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Canvas.Left" Value="{Binding}" />
                    <Setter Property="Canvas.Top" Value="{Binding}" />
                </Style>
            </ListBox.ItemContainerStyle>
            <ListBox.Items>
                <System:Int32>10</System:Int32>
                <System:Int32>30</System:Int32>
                <System:Int32>50</System:Int32>
                <System:Int32>70</System:Int32>
            </ListBox.Items>
        </ListBox>
    </StackPanel>
</UserControl>

【问题讨论】:

  • 感谢 skb,这回答了我的问题,即如何在 WPF 中执行此操作 :-) 正如您所说,它在 WPF 中效果很好。

标签: silverlight silverlight-3.0 listbox canvas


【解决方案1】:

我不确定它是否适用于您的场景,但我过去曾使用 RenderTransform 完成此操作。

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Green" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}">
                <TextBox.RenderTransform>
                    <TranslateTransform X="100" Y="100" />
                </TextBox.RenderTransform>
            </TextBox>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Items>
        <System:Int32>10</System:Int32>
        <System:Int32>30</System:Int32>
        <System:Int32>50</System:Int32>
        <System:Int32>70</System:Int32>
    </ItemsControl.Items>
</ItemsControl>

或者在绑定的情况下,您需要使用转换器

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas Background="Green" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBox Text="{Binding}" RenderTransform="{Binding Converter={StaticResource NumberToTransformGroupConverter}}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
    <ItemsControl.Items>
        <System:Int32>10</System:Int32>
        <System:Int32>30</System:Int32>
        <System:Int32>50</System:Int32>
        <System:Int32>70</System:Int32>
    </ItemsControl.Items>
</ItemsControl>

转换器

public void ConvertTo(object value, ...)
{
    int intValue = int.Parse(value.ToString());

    return new TransformGroup()
    {
        Children = new TransformCollection()
        {
            new TranslateTransform { X = intValue, Y = intValue }
        }
    };
}

【讨论】:

  • +1 在所展示的场景中,这已经足够好了。把它放在不够大的 ScrollViewer 或 Stackpanel 中,问题开始浮出水面。但是您唯一能做的就是全力以赴并编写一个自定义面板,以便可以在 Measure 和 Arrange 阶段提供所需的行为。
【解决方案2】:

Silverlight4 不绑定到样式中的附加属性。我建议使用 here 描述的 David Anson 的方法。

    <UserControl.Resources>
    <Style  x:Key="ScreenBindStyle" TargetType="ListBoxItem">
        <Setter Property="Helpers:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <Helpers:SetterValueBindingHelper>
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="Left" Binding="{Binding LocationField.Value.X}" />
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="Top" Binding="{Binding LocationField.Value.Y}" />
                    <Helpers:SetterValueBindingHelper Type="Canvas" Property="ZIndex" Binding="{Binding ZIndex.Value}" />
                </Helpers:SetterValueBindingHelper>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <ContentPresenter/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

在列表框中:

ItemContainerStyle="{StaticResource ScreenBindStyle}"

【讨论】:

    【解决方案3】:

    旧帖子,但我遇到了同样的问题,但现在使用 SL5,现在允许 Binding 在样式设置器中。我试图避免使用ListBox(因为它处理选择等),而ItemsControl 仍然没有ItemContainerStyle。所以我尝试了一些方法。

    我没有找到很多讨论这个问题的主题所以让我分享我的解决方案(对不起,如果它重复)

    其实我找到了一个很方便的方法来解决这个问题,在ItemsControl资源中添加一个未命名的Style

    <ItemsControl ItemsSource="{Binding Path=MyData}">
        <ItemsControl.Resources>
            <Style TargetType="ContentPresenter">
                <Setter Property="Canvas.Top" Value="{Binding Path=Bounds.Top}"/>
                <Setter Property="Canvas.Left" Value="{Binding Path=Bounds.Left}"/>
                <Setter Property="Width" Value="{Binding Path=Bounds.Width}"/>
                <Setter Property="Height" Value="{Binding Path=Bounds.Height}"/>
            </Style>
        </ItemsControl.Resources>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Canvas/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="my:DataType">
                ...
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
    

    像 SL5 中的魅力一样工作 :)

    【讨论】:

      【解决方案4】:

      我也无法解释你所看到的。您的 Xaml 至少在几个方面被破坏了。

      首先,Xaml 本身失败了,因为:-

      <Style TargetType="ContentPresenter">
      

      应该是

      <Style TargetType="ContentControl">
      

      ListBox 的情况下,项目容器的类型为ListBoxItem,它派生自ContentControl

      如果没有,在样式设置器中放置 {Binding} 仍然不起作用。我猜你是在想象样式将依次应用于每个项目并从当前项目中获取其值。然而,即使绑定在样式中起作用,也只会有 一个 样式,并且它会从 ListBox DataContext 获取其数据绑定。这是一个不同的DataContext,适用于每个 ListBox 项(在本例中是 Items 集合中的每个项)。

      我仍然认为 Ben 有一个合理的解决方案来消除这种方法。

      【讨论】:

      • 嗨,Anthony,我可能误读了您的答案,但据我所知,您在这里写的几乎所有内容都是不准确的。首先,xaml 不会因为目标类型而失败,事实上,如果您进行建议的更改,它会失败。其次,样式中的绑定确实有效。第三,绑定不会从列表框中获取其上下文,而是从列表框项中获取它。至于只有一种风格,我怀疑这种风格会被克隆。这里重要的是一开始提出的解决方案确实有效,我在 WPF 中使用它,但它在 Silverlight 中不起作用。
      • @MikeKulls:是的,你误读了我;)。让我从你的第二个反对意见开始,因为那是误解的真正根源。我声明“在样式设置器中放置 {Binding} 仍然不起作用”和“即使 if 绑定也起作用”。从那时起,这一切都是假设的,因为正如您所说,它不起作用。假设此时绑定已解决,Style 的 Value 属性将绑定到此 common 值(注意 不是 绑定本身),并将在跨平台使用所有项目。最后,即使 if 其他一切正常,TargetType is 也不正确。
      • 但是解决方案确实有效(我在哪里说它不起作用?),绑定在样式中有效。我几乎将此解决方案用作生产应用程序中的副本,我可以说它绝对有效。请记住,skb 声明该解决方案在 WPF 中有效,而不是在 silverlight 中。
      猜你喜欢
      • 1970-01-01
      • 2011-04-13
      • 1970-01-01
      • 2021-11-22
      • 2023-03-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-23
      相关资源
      最近更新 更多