简体   繁体   中英

WPF - Binding multiple values to a datagrind

UPDATED : Clean subject, and summarize it.

Hi, I've a datable filled, where each cell is a class like this

class CValue{
     public object Value;
     public Brush Quality;
     private int m_quality;

     public override String toString(){
           return Value.toString();
     }
}

My datagrid is bind on the datable, and it's working well. But my aim is to switch the background color of the cell depending of the Quality value.

I intend tu use datatemplate but don't know how it's working at all...

<dg:DataGrid  Name="DataGridResult" IsReadOnly="True" AutoGenerateColumns="False"
     BorderThickness="1" BorderBrush="{DynamicResource clBLACK}"
     CanUserReorderColumns="False"
     ItemsSource="{Binding Path=Result}">
          <dg:DataGrid.Resources>
             <Style TargetType="{x:Type dg:DataGridCell}">
                <Style.Setters>
                   <Setter Property="Background" Value="{Binding [1].Quality}"/>
                </Style.Setters>
             </Style>
          </dg:DataGrid.Resources>           
          <dg:DataGrid.ItemTemplate>
             <DataTemplate>
                <dg:DataGridCell>
                   </dg:DataGridCell>
             </DataTemplate>
           </dg:DataGrid.ItemTemplate>
</dg:DataGrid>

Actually, if the Value of the background's setter is set to "Blue", all cells are blued, so it's fine, but I can't find a way to bind it to my property. the [1] seems to return the column 1 of the row...

How to set to the cell dynamically ? 'Cause i've got a dynamic number of columns but there all of the CValue Type.

You should use DataTemplateSelector class to perform this logic. The scenario is described below:

  • Create the set of DataTemplates;
  • Derive from DataTemplateSelector Class and implement there logic of selecting appropriate DataTemplate as described in MSDN Article;
  • Define your custom DataTemplateSelector as the resource specifying the x:Key attribute;
  • Bind needed object to defined DataTemplateSelector resource.

UPDATE

The upper approach works best when you need to completely redesign cells as the guys mentioned in comment.

So for this task you should create your converter, define it as a resource and add it to your binding:

<!--somewhere in resources-->
<QualityToBackgroundConverter x:Key="qualityToBackgroundConverter "/>

then binding will look like:

Background="{Binding Quality, Converter={StaticResource qualityToBackgroundConverter }}" 

and finally the converter:

[ValueConversion(typeof(Quality), typeof(Brush))]
public class QualityToBackgroundConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value != null)
        {
            Quality quality = (Quality)value;           
            switch (quality)
            {
                case 0: return Brushes.Red;
                case 1: return Brushes.Yellow;
                case 2: return Brushes.Green;
                default: return Brushes.Transparent;
            }   
        }
        return Brushes.Transparent;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw NotImplementedException();
    }
}

One good way of doing this which keeps the coloring visible in the XAML is to use a style with binding to the quality. We put this style in the some resourcedictionary above the template, like in my case in the DataGrid.Resources.

<Controls:DataGrid>
    <Controls:DataGrid.Resources>
        <Style TargetType="{x:Type Controls:DataGridCell}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Quality}" Value="0">
                    <Setter Property="Background" Value="Red" />
                </DataTrigger>

                <DataTrigger Binding="{Binding Quality}" Value="0">
                    <Setter Property="Background" Value="Blue" />
                </DataTrigger>

            </Style.Triggers>
        </Style>
    </Controls:DataGrid.Resources>
    <Controls:DataGrid.ItemTemplate>
        <DataTemplate>
            <Controls:DataGridCell>
            </Controls:DataGridCell>
        </DataTemplate>
    </Controls:DataGrid.ItemTemplate>
</Controls:DataGrid>

Update:

To be able to databind the values or whatever use a converter like this:

[ValueConversion(typeof(int), typeof(SolidColorBrush))]
public class QualityToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Cast value
        int intValue = (int) value;

        if (intValue == 1)
            return new SolidColorBrush(Color.FromArgb(255, 255, 255, 255));

        return new SolidColorBrush(Color.FromArgb(255, 0, 0, 255));
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException("TwoWay binding not supported!");
    }
}

Bind it in the XAML like the follwing:

<Window.Resources>
    <WpfApplication1:QualityToColorConverter x:Key="ColorConverter" />
</Window.Resources>

<Controls:DataGridCell Background="{Binding Quality, Converter={StaticResource ColorConverter}}">
</Controls:DataGridCell>

Ok. So for an entire example databinding to the Brush of the model instead of using converters, styles etc. For the following cs -code:

class CValue
{
    public string Value { get; set; } // Notice we use properties for binding and not fields
    public Brush Quality { get; set; } // Notice we use properties for binding and not fields
    private int m_quality;

    public override String ToString()
    {
        return Value.ToString();
    }
} 

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        // Databind the list
        myGrid.ItemsSource = new List<CValue>
                          {
                              new CValue
                                  {
                                      Value = "First", 
                                      Quality = new SolidColorBrush(Color.FromArgb(255, 0, 255, 255))},
                              new CValue
                                  {
                                      Value = "Second",
                                      Quality = new SolidColorBrush(Color.FromArgb(255, 255, 0, 255))
                                  },
                              new CValue
                                  {
                                      Value = "Third", 
                                      Quality = new SolidColorBrush(Color.FromArgb(0, 255, 255, 255))
                                  }
                          };
    }
}

You would use a xaml for the rowstyle (notice the TargetType on the style and the AutoGenerateColumns="false" ) to bind the row-color and the value:

<Controls:DataGrid x:Name="myGrid" AutoGenerateColumns="False">

    <Controls:DataGrid.RowStyle>
        <Style TargetType="{x:Type Controls:DataGridRow}">
            <Setter Property="Background" Value="{Binding Quality}" />
        </Style>
    </Controls:DataGrid.RowStyle>

    <Controls:DataGrid.Columns>
        <Controls:DataGridTemplateColumn Header="Value">
            <Controls:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Label Content="{Binding Value}" />
                </DataTemplate>
            </Controls:DataGridTemplateColumn.CellTemplate>
        </Controls:DataGridTemplateColumn>
    </Controls:DataGrid.Columns>

</Controls:DataGrid>

Hope it helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM