2

I cannot say that I am new to WPF, because it would be too much. I just was given with WPF app to maintain...

I need to change particular cell color in DataGrid based on a value. I thought it would be easy, found that SO post: Change DataGrid cell colour based on values .

Pasted where it belongs, which gave me the following:

<DataGrid x:Name="DgDevices" ItemsSource="{Binding}" BorderThickness="2,0,2,2" Cursor="Cross">
    <DataGrid.ContextMenu>
        <ContextMenu >
            <MenuItem Header="Załóż Deblokadę" Click="InsertDBL"  />
            <MenuItem Header="Usuń Deblokadę" Click="RemoveDBL"/>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGridTextColumn Binding="{Binding Name}">
        <DataGridTextColumn.ElementStyle>
            <Style TargetType="{x:Type TextBlock}">
                <Style.Triggers>
                    <Trigger Property="Text" Value="1">
                        <Setter Property="Background" Value="Black"/>
                        <Setter Property="Foreground" Value="White"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGridTextColumn.ElementStyle>
    </DataGridTextColumn>
</DataGrid>

Now, when invoking Show method on this form, it gives me InvalidOperationException. I searched for explanation why this happens, but haven't found clear explanation.

Also, I know that Binding Name is placeholder for my binding (in <DataGridTextColumn Binding="{Binding Name}">), so I tired putting just Binding there (inspired by ItemsSource="{Binding}" in DataGrid node), but didn't solve the issue.

Michał Turczyn
  • 32,028
  • 14
  • 47
  • 69
  • 1
    Have you tried removing xaml until it works to cancel out and narrow down what the problem is... i don't know about you, but when i get weird errors, i find it an invaluable debugging tool – TheGeneral May 10 '18 at 07:23
  • As I explained, after pasting whole `` crashes the app (taken directly from mentioned post). Should I try and delete smaller parts? – Michał Turczyn May 10 '18 at 07:25
  • Thats what id do, remove small parts until it dosnt throw any more, add it back until you work out what line it is, then you can search for a more direct answer – TheGeneral May 10 '18 at 07:26
  • 1
    Could you post exception details? – Dennis May 10 '18 at 07:26

1 Answers1

4

You are now adding DataGridTextColumn right into DataGrid itself, not to its columns list. Adding items directly and using ItemsSource are mutually exclusive, so InvalidOperationException is thrown (and you didn't intend to add column as item anyway). Instead, do it like this:

<DataGrid x:Name="DgDevices"
          ItemsSource="{Binding}"
          BorderThickness="2,0,2,2"
          AutoGenerateColumns="False"
          Cursor="Cross">
    <DataGrid.ContextMenu>
        <ContextMenu >
            <MenuItem Header="Załóż Deblokadę" Click="InsertDBL"  />
            <MenuItem Header="Usuń Deblokadę" Click="RemoveDBL"/>
        </ContextMenu>
    </DataGrid.ContextMenu>
    <DataGrid.Columns> <!-- add to columns -->
        <DataGridTextColumn Binding="{Binding Name}">
            <DataGridTextColumn.ElementStyle>
                <Style TargetType="{x:Type TextBlock}">
                    <Style.Triggers>
                        <Trigger Property="Text"
                                 Value="1">
                            <Setter Property="Background"
                                    Value="Black" />
                            <Setter Property="Foreground"
                                    Value="White" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGridTextColumn.ElementStyle>
        </DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

Also, because you need to set AutoGenerateColumns to False, because otherwise DataGrid will automatically generate columns from your data source, in addition to columns you define manually, and you rarely need that.

Evk
  • 98,527
  • 8
  • 141
  • 191
  • I set in my code `DataContext` of `DataGrid`, which adds columns to already defined. Can I define all needed columns and fill them with `DataTable`? Or it will allways add `DataTable` column to existing ones? (Anyway, great answer, cleared a lot to me, +1 :) ) – Michał Turczyn May 10 '18 at 09:08
  • @MichałTurczyn not sure I understood correctly, but you I think you need to have a look at AutoGenerateColumns property of DataGrid. If set to true (default) - it will autogenerate columns based on your source. If you define your own column - you need to set that to false and define all columns yourself. Otherwise - it will add autogenerated columns _on top_ of columns you defined. – Evk May 10 '18 at 09:26
  • So, to apply your answer, I need to set it to false, define all column in XAML, then populate it? – Michał Turczyn May 10 '18 at 09:28
  • Yes, either all columns are autogenerated, or all columns are defined manually in xaml. Since you need to define at least one column manually - you need to define them all. – Evk May 10 '18 at 09:29
  • Great, very helpful and clear! Let me check fully your answer, then I'll accept it :) – Michał Turczyn May 10 '18 at 09:30