29

Tengo un poco de una situación compleja con WPF Treeview Binding. He pasado los últimos 2 días intentando Google, y this ha sido cerrado, pero no resuelve el problema.WPF Treeview Databinding Hierarchal Datos con tipos mixtos

Aquí está la situación:

Tengo un objeto que se parece a esto:

public class Category 
{ 
    public string Name { get; set; } 
    public List<Category> Categories { get; set; } 
    public List<Product> Products { get; set; } 
} 

public class Product 
{ 
    public string Name { get; set; 
} 

Cada categoría puede tener una lista de objetos y categorías secundarias. Tengo una razón para hacer esto que tiene mucho sentido para mí y para la aplicación que estoy escribiendo.

La construcción del objeto real puede ser algo como esto:

Category - Pharmacy 
    |-Product - Aspirin 
    |-Product - Tylenol 
    |-Category - Tooth Paste 
    | |-Product - Crest 
    | |-Product - Colgate 
    |-Category - Paper Products 
    |-Category - Toilet Paper 
    | |-Product - NoName 
    | |-Product - Charmin 
    |-Category - Facial Tissue 
     |-Product - Kleenex 
Category - Household 
    |-Product - Pinesol Cleaner 
    |-Product - Garbage Bags 

Ahora, estoy tratando de DataBind esta relación a una vista de árbol. Me gustaría que el TreeView se vea casi idéntico al constructo de objetos anterior.

hasta ahora tengo mi XAML Treeview aspecto:

<TreeView x:Name="CategoryList" Margin="8" Grid.Row="2" Grid.RowSpan="2" ItemsSource="{Binding Path=Categories}"> 
      <TreeView.Resources> 
       <HierarchicalDataTemplate DataType="{x:Type src:Category}" ItemsSource="{Binding Products}"> 
        <StackPanel> 
         <TextBlock Text="{Binding Path=Name}" /> 
        </StackPanel> 
       </HierarchicalDataTemplate> 
       <HierarchicalDataTemplate DataType="{x:Type src:Product}"> 
        <StackPanel> 
         <TextBlock Text="{Binding Path=Name}" /> 
        </StackPanel> 
       </HierarchicalDataTemplate> 
      </TreeView.Resources> 
     </TreeView> 

Esto funciona muy bien para la lista principal de categorías, y cada uno de sus productos sub. Pero no profundiza y muestra las subcategorías de cada categoría.

¿Hay alguna manera de hacerlo directamente con las plantillas para que cada elemento (categoría o producto) esté seleccionado? Estoy usando un patrón MVVM y no quiero recurrir al uso del código, pero lo haré si es necesario.

Respuesta

46

Dado que desea que los elementos en TreeView tengan una lista de elementos secundarios que consta de ambos Productos de Categorías, querrá que su Categoría ViewModel tenga una colección que consta de Categorías y Productos. Por ejemplo, se puede utilizar un CompositeCollection combinar sus colecciones existentes:

public class Category 
{ 
    public string Name { get; set; } 
    public List<Category> Categories { get; set; } 
    public List<Product> Products { get; set; } 

    public IList Children 
    { 
     get 
     { 
      return new CompositeCollection() 
      { 
       new CollectionContainer() { Collection = Products }, 
       new CollectionContainer() { Collection = Categories } 
      }; 
     } 
    } 
} 

(En código real, es probable que desee mantener una referencia al mismo objeto de recogida en lugar de crear uno nuevo cada vez.)

Luego, en su HierarchicalDataTemplate, utilice la lista combinada como el ItemsSource:

<HierarchicalDataTemplate DataType="{x:Type src:Category}" 
          ItemsSource="{Binding Children}"> 

los artículos serán una mezcla de objetos producto y categoría, y WPF utilizarán el DataTemplate apropiado para cada uno.

+2

Esta es una solución perfecta, ¡gracias! Al igual que una nota para cualquier otra persona, el orden en que agrega los contenedores de recolección a la colección compuesta es el orden en que aparecen en la vista de árbol. Si agrega las categorías primero, aparecerán antes de los productos – thorkia