2010-01-29 10 views
5

J'ai une question sur la liaison de données DataGrid dans WPF. J'utilise le VS 2010 Beta 2 qui a son propre DataGrid, pas le Toolkit, même si je pense que c'est à peu près la même chose. Je veux associer à un jeu de données contenant 52 colonnes, une pour chaque semaine de l'année. Pour cette raison, je veux lier dynamiquement les données plutôt que de spécifier chaque champ. La valeur de chaque champ est vraie ou fausse selon certaines conditions. Basé sur cette valeur je veux montrer une image dans le modèle de cellule si la condition est vraie et la cacher si la condition n'est pas vraie. Mon problème est que tous les exemples d'utilisation des modèles que j'ai trouvés se réfèrent au cas de champs prédéfinis fixes, où vous pouvez avoir une liaison comme Text = "{Binding UserName}". Ce n'est pas bon pour moi parce que je ne sais pas ce que les noms de champs seront au moment du design.Liaison dynamique dans WPF DataGridCell Modèle

J'ai inventé un exemple simplifié qui illustre le problème. Dans cet exemple, une table de données contenant des valeurs true et false est générée. L'image de mon modèle n'est jamais visible. Comment le rendre invisible en fonction de la valeur vraie ou fausse des données?

<Window.Resources> 

    <!--This is the bit that doesn't work...--> 
    <Style TargetType="{x:Type Image}" x:Key="HideWhenFalse"> 
     <Setter Property="Visibility" Value="Hidden" /> 
     <Style.Triggers> 
      <DataTrigger 
     Binding="{Binding Path=???}" 
     Value="True"> <!--What to put for the path? --> 
       <Setter Property="Visibility"> 
        <Setter.Value> 
         Visible 
        </Setter.Value> 
       </Setter> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
    <!--Up to here--> 

    <Style x:Key="{x:Type DataGridCell}" TargetType="{x:Type DataGridCell}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate> 
        <StackPanel> 
         <Image Source="Images/tick.bmp" Style="{StaticResource HideWhenFalse}"> 

         </Image> 
        </StackPanel> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

<Grid> 
    <DataGrid 
     x:Name="myDataGrid" 
     AutoGenerateColumns="True" > 

    </DataGrid> 
</Grid> 

code derrière:

public partial class MainWindow: Fenêtre {

public MainWindow() 
{ 
    InitializeComponent(); 

    DataTable dtTable = new DataTable(); 

    dtTable.Columns.Add("A", typeof(Boolean)); 
    dtTable.Columns.Add("B", typeof(Boolean)); 
    dtTable.Columns.Add("C", typeof(Boolean)); 
    dtTable.Columns.Add("D", typeof(Boolean)); 
    dtTable.Columns.Add("E", typeof(Boolean)); 
    dtTable.Columns.Add("F", typeof(Boolean)); 

    for (int i = 0; i < 5; i++) 
    { 
     object[] oValues = new Object[dtTable.Columns.Count]; 

     for (int j = 0; j < dtTable.Columns.Count; j++) 
     { 
      oValues[j] = (j % 2 == 1) ? true : false; 
     } 

     dtTable.Rows.Add(oValues); 
    } 

    myDataGrid.ItemsSource = dtTable.DefaultView; 
    myDataGrid.Items.Refresh(); 
} 

}

NB Ceci est probablement évident et j'aborde le problème de manière complètement erronée. Voici une confession: Depuis quelques mois, j'essaie de comprendre WPF et il me semble toujours que j'aborde tous les problèmes de la mauvaise façon. J'espère que le penny tombera bientôt.

Répondre

9

Vous pouvez utiliser un MultiBinding, avec une première liaison prenant le contexte de données réel de la cellule (qui serait la ligne) et le second prenant la colonne. De là, vous pouvez récupérer la valeur de la cellule.

Code Converter:

public class RowColumnToCellConverter : IMultiValueConverter { 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { 
     DataRowView row = values[0] as DataRowView; 
     DataGridColumn column = values[1] as DataGridColumn; 
     return row != null && column != null 
      ? row[column.SortMemberPath] 
      : DependencyProperty.UnsetValue; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { 
     throw new NotSupportedException(); 
    } 
} 

XAML:

<Style x:Key="{x:Type DataGridCell}" TargetType="{x:Type DataGridCell}"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate> 
        <StackPanel> 
         <TextBlock x:Name="TextOK" Text="OK" Visibility="Collapsed" /> 
        </StackPanel> 
        <ControlTemplate.Triggers> 
         <DataTrigger Value="True"> 
          <DataTrigger.Binding> 
           <MultiBinding Converter="{StaticResource RowColumnToCellConverter}"> 
            <Binding /> 
            <Binding RelativeSource="{x:Static RelativeSource.Self}" Path="Column" /> 
           </MultiBinding> 
          </DataTrigger.Binding> 
          <Setter TargetName="TextOK" Property="Visibility" Value="Visible" /> 
         </DataTrigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 

J'ai utilisé un TextBlock à la place une image pour le test, mais le code sera le même. Évitez simplement de définir un style pour l'image si cela peut être fait directement dans le style de DataGridCell.

+0

Merci pour votre réponse très rapide, Julien. Cela fonctionne un régal. – Richard

+1

@Richard - vous devriez accepter cette réponse – David

+0

merci bien, ça m'a beaucoup aidé! – David