2010-01-29 15 views
5

Tengo una pregunta sobre el enlace de datos DataGrid en WPF. Estoy usando VS 2010 Beta 2, que tiene su propia DataGrid, no Toolkit, aunque creo que es prácticamente la misma.Enlace dinámico en la plantilla WGT DataGridCell

Quiero enlazar a un conjunto de datos que tiene 52 columnas, una para cada semana del año. Por esta razón, quiero vincular los datos dinámicamente en lugar de especificar cada campo. El valor para cada campo es verdadero o falso dependiendo de alguna condición. En función de este valor, quiero mostrar una imagen en la plantilla de la celda si la condición es verdadera y ocultarla si la condición no es verdadera.

Mi problema es que todos los ejemplos de uso de plantillas que he encontrado se refieren al caso de campos predefinidos fijos, donde puede tener un enlace como Text = "{Binding UserName}". Esto no es bueno para mí porque no sé cuáles serán los nombres de los campos en el momento del diseño.

He creado un ejemplo simplificado que ilustra el problema. En este ejemplo, se genera una tabla de datos que contiene valores verdaderos y falsos. La imagen en mi plantilla nunca es visible. ¿Cómo lo haría invisible dependiendo del valor verdadero o falso en los datos?

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

Código atrás:

pública parcial de clase MainWindow: Ventana {

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 Esto es probablemente obvio y estoy abordando el problema de una manera completamente incorrecta. Aquí hay una confesión: he estado tratando de entender cómo funciona WPF durante un par de meses y aún me parece que me estoy acercando a CADA problema de la manera incorrecta. Espero que el centavo caiga pronto.

Respuesta

9

Puede usar un MultiBinding, con un primer enlace tomando el contexto de datos real de la celda (esa sería la fila), y el segundo tomando la columna. A partir de ahí, puede recuperar el valor de la celda.

Convertidor de código:

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> 

he usado una vez una imagen TextBlock para las pruebas, pero el código será el mismo. Simplemente evite definir un estilo para la imagen si eso se puede hacer directamente en el estilo DataGridCell.

+0

Gracias por su pronta respuesta, Julien. Funciona un regalo. – Richard

+1

@Richard - debe aceptar esta respuesta – David

+0

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

Cuestiones relacionadas