在Gridlight 3中使用Grid作为ItemsControl的ItemsPanel

时间:2010-03-06 03:35:09

标签: silverlight silverlight-3.0 grid

是否可以做这样的事情:

    <ListBox>
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Text}" Grid.Column="{Binding Column}" Grid.Row="{Binding Row}"  />
            </DataTemplate>                
        </ListBox.ItemTemplate>
    </ListBox>

项目源类似于具有文本,列和行属性的对象列表。

这可能吗?我真的希望我的数据网格是数据绑定的。

6 个答案:

答案 0 :(得分:3)

你所拥有的东西将无法工作,因为Silverlight将每个项目 - 每个DataTemplate实例 - 包装在一个ListBoxItem中,而Grid.Column和Grid.Row附加的属性需要应用于该ListBoxItem,而不是TextBox,它成为该ListBoxItem的内容。

好消息是你可以使用ListBox.ItemContainerStyle在隐式ListBoxItem上设置属性。

坏消息是ItemContainerStyle不支持绑定。因此,您无法使用它将Grid.Column和Grid.Row附加属性设置为手头数据项的属性。

我使用的一个解决方案是继承ListBox并在PrepareContainerForItemOverride中设置绑定。这是一个非常粗糙,硬连线的例子:

public class GriderrificBox : ListBox
{
  protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
  {
    base.PrepareContainerForItemOverride(element, item);

    FrameworkElement fe = element as FrameworkElement;
    if (fe != null)
    {
      BindingOperations.SetBinding(fe, Grid.RowProperty,
        new Binding { Source = item, Path = new PropertyPath("Row") });
      BindingOperations.SetBinding(fe, Grid.ColumnProperty,
        new Binding { Source = item, Path = new PropertyPath("Column") });
    }
  }
}

用法:

<local:GriderrificBox>
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBox Text="{Binding Text}" />
    </DataTemplate>
  </ListBox.ItemTemplate>
  <ListBox.ItemsPanel>
    <ItemsPanelTemplate>
      <Grid />
    </ItemsPanelTemplate>
  </ListBox.ItemsPanel>
</local:GriderrificBox>

此代码至少有两个主要的uglinesses:首先,您仍需要在XAML中明确指定ItemsPanel,即使该控件仅适用于Grid面板;第二,绑定路径硬连线到代码中。第一个可以通过使用普通控件默认样式机制来解决,第二个可以通过定义属性,如RowBindingPath和ColumnBindingPath,PrepareItemForContainerOverride可以参考而不是使用硬连线路径。希望足够让你去!

答案 1 :(得分:2)

Grid仅适用于您尝试将其用于此处的用法。在开始向单元格分配元素之前,它期望预先定义可用行和列的集合。

如果您尝试创建一个使用水平和垂直空间的列表框,那么Silverlight Toolkit中的WrapPanel可能是更好的基础。

另一方面,如果您尝试创建“数据网格”,请考虑对模型中每行的列进行转置或分组,然后您可以使用DataGrid代替ListBox

答案 2 :(得分:2)

我找到了另一个有趣的解决方案: http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/

示例是使用ItemsCountrol完成的 - 但我很确定它也适用于ListBox

结果如下:

<ItemsControl ItemsSource="{Binding}">  
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <!-- use the ItemsPerRow attached property to dynamically add rows -->
      <Grid local:GridUtils.ItemsPerRow="1"
          ShowGridLines="True"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding}"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

并且确实需要实现local:GridUtils.ItemsPerRow附加属性。

答案 3 :(得分:2)

仅当您知道需要多少行和列且仅在Silverlight 5中时才会有效。(您无法在silverlight 4中的setter属性中绑定值。)

<Grid x:Name="LayoutRoot" Background="White">
        <ItemsControl x:Name="ic" Background="#FFE25454">
            <ItemsControl.Resources>
                <Style TargetType="ContentPresenter">
                    <Setter Property="Grid.Row" Value="{Binding X}"/>
                    <Setter Property="Grid.Column" Value="{Binding Y}"/>
                </Style>
            </ItemsControl.Resources>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid ShowGridLines="True">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                            <RowDefinition Height="*"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions></Grid>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>

                    <TextBlock Text="{Binding text}"/>

                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

答案 4 :(得分:0)

如果您有兴趣在将来版本的Silverlight中支持此类场景,请投票选择porting of Adobe Flex Grid layout,这将在此类场景中完美运行

答案 5 :(得分:-1)

您只需要为Grid创建两个附加属性(类似于ColumnsNumber和RowsNumber,它们将填充ColumnDefinitions和RowDefenitions集合)。然后覆盖ItemsControl中的默认ItemContainerStyle(因为ItemsControl中的所有项目都由ContentPresenters包装)。代码示例:

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Grid
                behavior:GridBehavior.ColumnsNumber="{Binding}"
                behavior:GridBehavior.RowsNumber="{Binding}">
            </Grid>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <ItemsControl.ItemsSource>
        <Binding />
    </ItemsControl.ItemsSource>

    <ItemsControl.ItemTemplate>
        <DataTemplate />
    </ItemsControl.ItemTemplate>

    <ItemsControl.ItemContainerStyle>
        <Style TargetType="ContentPresenter">
            <Setter Property="Grid.Column" Value="{Binding}" />
            <Setter Property="Grid.Row" Value="{Binding}" />
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>