2009-04-23 12 views
10

Tengo una lista de AvailableItems que quiero mostrar como una lista de casillas de verificación, para que los usuarios puedan elegir qué elementos generar, que luego se almacenan en otra lista llamada ItemsToGenerate (mis listas son en realidad solo listas de cadenas).¿Cuál es la forma más sencilla de vincular una lista de casillas de verificación a una lista de valores comprobados

Mostrando todos los elementos disponibles con casillas de verificación correspondientes es fácil:

<ItemsControl ItemsSource="{Binding Path=AvailableItems}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <CheckBox Content="{Binding}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate>  
</ItemsControl> 

Pero ahora necesitan de obligar a cada Checkbox.IsChecked propiedad, al hecho de que el artículo esté en la lista ItemsToGenerate. Pensé en hacer una ListContainmentToBoolConverter así:

IsChecked="{Binding Path=ItemsToGenerate, 
      Converter={StaticResource ListContainmentToBoolConverter}}" 

Pero eso no funciona porque me falta un ConverterParameter para pasar el valor de cada elemento, pero no puedo hacer eso, porque no es compatible con ConverterParameter Unión.

¿Alguna idea?

Respuesta

12

He encontrado una solución a mi problema.

he cambiado de ItemsControl a un ListBox, y añadió una unión entre los SelectedItems con mi colección ItemsToGenerate utilizando la técnica descrita here. Básicamente, me permite sincronizar cualquier colección personalizada al ListBox.SelectedItems usando una propiedad adjunta simple.

<ListBox ItemsSource="{Binding AvailableItems}" 
     Behaviors:MultiSelectorBehaviours.SynchronizedSelectedItems= 
      "{Binding ItemsToGenerate}" 
     SelectionMode="Multiple" 
     Background="{x:Null}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <WrapPanel />      
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <CheckBox Content="{Binding}" 
         Margin="3" 
         IsChecked="{Binding RelativeSource= 
          {RelativeSource Mode=FindAncestor, 
          AncestorType={x:Type ListBoxItem}}, 
          Path=IsSelected}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate> 
</ListBox> 

sigo siendo capaz de mostrar esto como principio queríamos (una lista de casillas de verificación), mediante la adición de una plantilla de datos para cambiar cada ListBoxItem a una casilla de verificación y vinculante cada Checkbox.IsChecked a ListBoxItem.IsSelected.

Tenía este patrón en tantos lugares de mi aplicación que esta es la solución ideal para mí, porque ahora solo necesito especificar una propiedad adjunta, y el resto es manejado por los enlaces de datos, y no lo hago Necesito cualquier código adicional.

+1

Me gustaría ver la implementación de su propiedad adjunta. Lamentablemente, esto solo funciona si reutiliza la selección de ListBox, pero ¿qué ocurre si utiliza un control de elementos con una casilla dentro de la plantilla? – jpierson

+0

Intenté esto y el resultado final es un poco funky (http://i.imgur.com/ZRyrjfe.png). Me voy a quedar con un ListBox simple, personalmente. – Chris

6

Honestamente crearía una lista de objetos que contienen tanto la cadena como un booleano que indica si está marcada.

Con un poco de Linq puede generar su lista de objetos y vincularla a itemSource en lugar de enlazar la lista de cadenas.

Al final será más sencillo, especialmente si realmente necesita actualizar algo si el usuario puede marcar o desmarcar las casillas de verificación.

actualización == ==

en respuesta al comentario, mi opinión sobre esto porque no estoy seguro de entender cuál es el problema real sería: siempre y cuando tengamos la lista completa (AvailableItems) y la lista artículos seleccionados de (ItemsToGenerate):

public class ItemEntry 
{ 
    public string Name { get; set; } 
    public bool IsSelected {get; set; } 
} 

...

_Items = from item in AvailableItems 
      select new ItemEntry() { 
        Name = item, 
        IsSelected = ItemsToGenerate.contains(item) 
        }).ToList(); 

a continuación, puede vincular a su lista como tal, mediante la exposición de _Items como una propiedad denominada artículos:

<ItemsControl ItemsSource="{Binding Path=Items}"> 
    <ItemsControl.ItemTemplate> 
     <DataTemplate> 
      <CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}" /> 
     </DataTemplate> 
    </ItemsControl.ItemTemplate>  
</ItemsControl> 

Más adelante puede seleccionar desde _Elementos donde IsSelected es verdadero para obtener los elementos seleccionados si es necesario.

Además, si ItemsToGenerate puede agrandarse, debe crear un HashSet de los valores y usarlo en la consulta, lo que lo haría más rápido si fuera necesario.

+0

La razón por la que no quiero hacer eso es porque mis datos se guardan en xml y se editan a mano algunas veces. Entonces, si hay 300 elementos disponibles y solo quieren generar 2 elementos, quiero que solo escriban Item1 Item2. –

+0

ver mi actualización para ver si me falta algo. –

+0

He pensado en otra forma de hacerlo: usar un ListBox donde la plantilla del elemento enlaza la casilla de verificación. Se comprueba en ListItem.IsSelected. Entonces solo sería cuestión de enlazar ItemsSource a AvailableItems y vincular los SelectedItems a ItemsToGenerate. –

Cuestiones relacionadas