2009-02-20 8 views
2

Quelqu'un peut-il me dire s'il est possible de créer et d'ajouter des données à une grille de données WPF Toolkit non liée.Création manuelle d'une grille de données non liée

S'il est en effet possible de faire, quelqu'un peut-il s'il vous plaît donner un exemple de ce qui suit:

Programmatically: créer un DataGrid créer un DataGridTextColumn ajouter le DataGridTextColumn au DataGrid créer un datagridrow ensemble le texte de la colonne dataagridtext pour la ligne à "tester" ajouter le datagridrow à la grille de données

Je voudrais créer un DataGrid qui est unbound. Ma raison est que je voudrais créer une colonne modèle avec plusieurs contrôles de différents types et nombres - 2 cases à cocher, 4 radiobuttons, 5 cases à cocher, etc. - qui sont ajoutés dynamiquement à l'exécution et puisque le type et le nombre sont inconnus. un moyen de les documenter. Je suis heureux de travailler sans être lié.

Merci d'avance!

[Edit: Je n'ai pas encore trouvé une réponse appropriée à cette question et ont commencé une prime]

Répondre

1

Vous pouvez utiliser UserControl pour créer les contrôles souhaités.

Window1.xaml (extrait)

<dg:DataGrid ItemsSource="{Binding}" CanUserAddRows="False" AutoGenerateColumns="False"> 
    <dg:DataGrid.Columns> 

     <dg:DataGridTemplateColumn Header="Test" MinWidth="100"> 
      <dg:DataGridTemplateColumn.CellTemplate> 
       <DataTemplate> 
        <my:ControlA Foo="{Binding}"></my:ControlA> 
       </DataTemplate> 
      </dg:DataGridTemplateColumn.CellTemplate> 
     </dg:DataGridTemplateColumn> 

    </dg:DataGrid.Columns> 
</dg:DataGrid> 

Window1.xaml.cs

public partial class Window1 : Window 
{ 
    List<Foo> _items = new List<Foo>(); 

    public Window1() 
    { 
     InitializeComponent(); 

     _items.Add(new Foo { CheckBoxCount = 2, TextBoxCount = 1 }); 
     _items.Add(new Foo { CheckBoxCount = 3, TextBoxCount = 0 }); 

     DataContext = _items; 
    } 
} 

ControlA.xaml

<UserControl x:Class="Demo.ControlA" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <StackPanel x:Name="_placeHolder"> 
    </StackPanel> 
</UserControl> 

ControlA.xaml.cs

public partial class ControlA : UserControl 
{ 
    public ControlA() 
    { 
     InitializeComponent(); 

     Loaded += new RoutedEventHandler(ControlA_Loaded); 
    } 

    void ControlA_Loaded(object sender, RoutedEventArgs e) 
    { 
     if (Foo != null) 
     { 
      for (int it = 0; it < Foo.CheckBoxCount; it++) 
       _placeHolder.Children.Add(new CheckBox()); 

      for (int it = 0; it < Foo.TextBoxCount; it++) 
       _placeHolder.Children.Add(new TextBox()); 
     } 
    } 

    public static readonly DependencyProperty FooProperty = 
     DependencyProperty.Register("Foo", typeof(Foo), typeof(ControlA)); 

    public Foo Foo 
    { 
     get { return (Foo)GetValue(FooProperty); } 
     set { SetValue(FooProperty, value); } 
    } 
} 

Foo.cs

public class Foo 
{ 
    public int TextBoxCount { get; set; } 
    public int CheckBoxCount { get; set; } 
} 

Hope this helps.

P.S. Il devrait être possible de refactor DataGridTemplateColumn dans UserControl séparé.

+0

Votre réponse semble plutôt bonne. Je vais faire des tests rapides et, si tout va bien, la prime est à vous! Merci de votre aide! –

+0

Merci pour votre aide Alex! La générosité est à vous. –

+0

Glad cela vous a aidé. – alex2k8

1

Je ne l'ai jamais utilisé une grille sans le liant à quelque chose.

MAIS regardant la raison sous-jacente, qui peut être résolu tout en utilisant la liaison de données. Par exemple: Si vous utilisez une classe ViewModel pour votre objet auquel la grille est liée, vous pouvez faire d'un aspect de cette classe les accesseurs de visibilité pour les différents contrôles.

Dans l'objet, vous auriez ceci:

Public ReadOnly Property CheckboxAVisibility As Windows.Visibility 
    Get 
    ' Do Logic 
    Return Visiblity 
    End Get 
End Property 

Et dans le XAML que vous feriez:

<CheckBox IsChecked="{Binding IsBoxAChecked}" Visibility={Binding CheckboxAVisibility}" /> 

Cela rend aussi les choses plus faciles, comme vous serez en mesure de modifier la visibilité des différents contrôles en modifiant d'autres contrôles dans la rangée (ex: en décochant CheckboxA provoque l'apparition de RadioButtons B, C & D). Une deuxième option consisterait à lister uniquement les informations "En-tête" dans la grille, et lorsque l'utilisateur double-clique sur une ligne, vous affichez un éditeur avec les aspects éditables dans un panneau ou une fenêtre secondaire (similaire à la façon dont MVC édite travaux).

modifier en raison de commentaires

Voici une autre suggestion, plutôt que d'un DataGrid, utilisez un StackPanel. Pour chaque ligne dont vous avez besoin, vous pouvez ajouter un panneau de grille ou un panneau de pile ou quelque chose de similaire, créé au moment de l'exécution selon vos règles.Par exemple:

XAML:

<StackPanel Name="stkItems" Orientation="Vertical" /> 

code:

Public Sub AddItems(dt as DataTable) 
    For Each row As DataRow in dt.Rows 
    Select Case row("Which") 
      Case 1: 
      Dim i As New Checkbox 
      i.Content = "Foo" 
      i.IsChecked = row("Content") 
      stkItems.Children.Add(i) 
      Case 2: 
       Dim i as New TextBox 
       i.Text = row("Content") 
       stkItems.Children.Add(i) 
    End Select 
    Next 
End Sub 

Ceci est très simplifié, et vous pourriez faire des choses telles que des contrôles utilisateur prédéfinis que vous pouvez utiliser, ou tout simplement construire une tas de contrôles dans un conteneur défini par programme, puis ajoutez-le au StackPanel

+0

L'approche ViewModel est quelque chose que j'ai considéré. Cependant, je n'arrive pas à comprendre comment surmonter l'obstacle fondamental de ne pas savoir pour une rangée donnée, quel type de contrôles j'aurai et combien j'en aurai. Il n'est pas possible de coder en dur un certain nombre et de définir leur visibilité. –

+0

Vous pourriez être plus heureux en évitant la grille de données puis - regardez mes modifications –

+0

Malheureusement c'est ce que je devais faire avant de poster cette question. J'espérais qu'il y avait une autre option car certaines des fonctionnalités de DataGrid intégrées sont vraiment sympa! –

0

J'ai créé une classe DataGridUnboundedColumn simple dérivée de DataGridBoundColumn et peut être utilisée pour fournir du texte personnalisé de FrameworkElement pour la cellule.

Vous vous abonnez simplement à l'événement CellFormating et définissez CellElement dans EventArgs sur l'élément personnalisé qui sera affiché. Il est également possible de définir simplement CellText dans EventArgs - dans ce cas, le TextBlock avec CellText sera affiché dans la grille.

Les exemples ci-dessous montre comment l'utiliser:

XAML:

<dg:DataGrid Name="DataGrid1" AutoGenerateColumns="False"> 
    <dg:DataGrid.Columns> 
     <dg:DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/> 
     <myColumn:DataGridUnboundedColumn x:Name="AddressColumn" Header="Address" /> 
    </dg:DataGrid.Columns> 
</dg:DataGrid> 

CODE:

public MyPage() 
    { 
     InitializeComponent(); 

     AddressColumn.CellFormating += new UnboundedColumnEventHandler(AddressColumn_CellFormating); 
    } 

    void AddressColumn_CellFormating(object sender, UnboundedColumnEventArgs e) 
    { 
     IPerson person; 

     person= e.DataItem as IPerson; 

     if (person!= null) 
      e.CellText = string.Format("{0}, {1} {2}", person.Address, person.PostalCode, person.City); 
    } 

La mise en œuvre de DataGridUnboundedColumn est ici:

class DataGridUnboundedColumn : DataGridBoundColumn 
{ 
    public event UnboundedColumnEventHandler CellFormating; 

    public DataGridUnboundedColumn() 
    { 
     this.IsReadOnly = true; 
    } 

    protected override FrameworkElement GenerateEditingElement(DataGridCell cell, object dataItem) 
    { 
     return null; 
    } 

    protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) 
    { 
     FrameworkElement shownElement; 
     UnboundedColumnEventArgs eventArgs; 

     if (CellFormating == null) 
      return null; 


     eventArgs = new UnboundedColumnEventArgs(cell, dataItem); 

     // call the event 
     CellFormating(this, eventArgs); 

     shownElement = null; 

     // check the data set in the eventArgs 
     if (eventArgs.CellElement != null) 
     { 
      // show the set eventArgs.CellElement 
      shownElement = eventArgs.CellElement; 
     } 
     else if (eventArgs.CellText != null) 
     { 
      // show the CellText in TextBlock 
      TextBlock textBlock = new TextBlock(); 
      textBlock.Text = eventArgs.CellText; 

      shownElement = textBlock; 
     } 
     else 
     { 
      // nothing set 
     } 

     return shownElement; 
    } 
} 

public delegate void UnboundedColumnEventHandler(object sender, UnboundedColumnEventArgs e); 

public class UnboundedColumnEventArgs : EventArgs 
{ 
    public DataGridCell Cell { get; set; } 
    public object DataItem { get; set; } 

    /// <summary> 
    /// The subscriber of the event can set the CellText. 
    /// In this case the TextBlock is used to display the text. 
    /// NOTE that if CellElement is not null, the CellText will not be used but insted a CellElement will be shown 
    /// </summary> 
    public string CellText { get; set; } 

    /// <summary> 
    /// The subscribed can set the FrameworkElement that will be shown for this cell. 
    /// If the CellElement is null, the CellText will be used to show the TextBlock 
    /// </summary> 
    public FrameworkElement CellElement { get; set; } 

    public UnboundedColumnEventArgs() 
     : base() 
    { } 

    public UnboundedColumnEventArgs(DataGridCell cell, object dataItem) 
     : base() 
    { 
     Cell = cell; 
     DataItem = dataItem; 
    } 
} 
Questions connexes