2010-03-06 5 views
11

¿Es posible hacer algo como esto:utilizando una cuadrícula como el ItemsPanel de ItemsControl en Silverlight 3

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

La fuente artículos sería algo así como una lista de objetos que tenían el texto, columnas y filas propiedades.

¿Esto es posible? Realmente quiero que mi cuadrícula de datos esté unida a los datos.

+0

no está claro lo que intenciones completas son. ¿Estás realmente detrás de la semántica de ListBox que es una lista (que posiblemente requiera desplazamiento) de N elementos donde se pueden seleccionar uno o más? – AnthonyWJones

Respuesta

3

Lo que tenga no funcionará porque Silverlight ajusta cada elemento, cada instancia de DataTemplate, en un ListBoxItem, y las propiedades adjuntas Grid.Column y Grid.Row deben aplicarse a ese ListBoxItem, no a el TextBox que se convierte en el contenido de ese ListBoxItem.

La buena noticia es que puede establecer atributos en el ListBoxItem implícito utilizando ListBox.ItemContainerStyle.

La mala noticia es que ItemContainerStyle no admite el enlace de forma inmediata. Por lo tanto, no puede usarlo para establecer las propiedades adjuntas Grid.Column y Grid.Row a los atributos del elemento de datos en cuestión.

Una solución que he utilizado es subclase ListBox y configurar el enlace en PrepareContainerForItemOverride. He aquí una muy cruda, ejemplo de cableado:

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") }); 
    } 
    } 
} 

Uso:

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

Hay (al menos) dos principales fealdades con este código: en primer lugar, usted todavía tiene que especificar explícitamente ItemsPanel en XAML, incluso aunque el control solo funciona con paneles de cuadrícula; y segundo, las rutas de enlace están cableadas en el código. El primero se puede abordar utilizando el mecanismo de estilo predeterminado de control normal, y el segundo definiendo propiedades como RowBindingPath y ColumnBindingPath que PrepareItemForContainerOverride puede consultar en lugar de utilizar rutas cableadas. ¡Con suerte lo suficiente para que te vayas!

+0

Todavía existe el problema de que un 'Grid' requiere que el conjunto de Filas y Columnas se defina en su colección' RowDefinitions' y 'ColumnDefinitions'. – AnthonyWJones

+0

No sé si esto funciona. Parte del problema es que no hay BindingOperations (al menos eso puedo encontrar) en SL3. Intenté simplemente hacer un SetBinding en el objeto del elemento, pero tampoco funcionó. itowlson: ¿Has conseguido esto para trabajar con SL3? – skb

+0

BindingOperations es una clase estática en el espacio de nombres System.Windows.Data. Sí, he tenido esto trabajando con SL3 (aunque usando un Canvas en lugar de un Grid, pero el concepto es el mismo, con el debido reconocimiento al tema planteado por AnthonyWJones). – itowlson

2

El Grid simplemente no es adecuado para el uso que está tratando de poner aquí. Espera que el conjunto de filas y columnas disponibles se definan por adelantado antes de comenzar a asignar elementos a las celdas.

Si está intentando crear un cuadro de lista que utilice el espacio horizontal y vertical, quizás una mejor base sería WrapPanel del kit de herramientas de Silverlight.

Por otro lado, si usted está tratando de crear una "red de datos" y luego considerar la transposición o agrupar las columnas en cada fila en el modelo, a continuación, puede utilizar la DataGrid en lugar de un ListBox

0

Si está interesado en apoyar este escenario en la versión futura de Silverlight vote por porting of Adobe Flex Grid layout, que funcionará perfectamente en tal escenario

-1

Solo necesita crear dos propiedades adjuntas para Grid (algo así como ColumnsNumber y RowsNumber que llenarían las colecciones ColumnDefinitions y RowDefenitions) Y luego anula ItemContainerStyle por defecto en ItemsControl (porque todos los elementos en ItemsControl envueltos por ContentPresenters).Código de ejemplo:

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

No hay ItemContainerStyle en Silverlight. – Paul

2

he encontrado otro interesante solución para este problema: http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/

El Ejemplo se hace con un ItemsCountrol -, pero estoy bastante seguro de que también funciona con un ListBox

El resultado se ve así:

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

y necesita implementar un local:GridUtils.ItemsPerRow propiedad adjunta.

2

Esto funcionará sólo si conoce el número de filas y columnas que necesita y sólo en Silverlight 5. (No se puede enlazar el valor de la propiedad colocador en Silverlight 4.)

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