Click here to Skip to main content
15,920,438 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi people.
I have a DataGrid in WPF.
There are two columns in it.
All datas at the first column are a rectangle (I mean as Shape).
There is a button in the window, that when user hits the button, it fills the Rectangle of row 35, to Red.

But I don't know why VS gives me exception that it is nothing!

Would you please kindly help me on this?

What I have tried:

<Window x:Class="MainWindow"
        Title="MainWindow" Height="450" Width="800">
        <DataGrid x:Name="DGEditing"
                <DataGridTemplateColumn Header="" IsReadOnly="True" Width="2*">
                            <Rectangle Height="Auto" RadiusX="5" RadiusY="3.5" Fill="Black">
                <DataGridTextColumn Header="Character" IsReadOnly="False" Width="22*" Binding="{Binding Path=CharacterName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
        <Button Content="Button" HorizontalAlignment="Left" Margin="650,149,0,0" VerticalAlignment="Top" Height="91" Width="91" Click="Button_Click"/>

Class MainWindow
    Public Class TemporaryItemsClass
        Public Property Rct As Boolean
        Public Property CharacterName As String
    End Class
    Public TemporaryItems As New System.Collections.ObjectModel.ObservableCollection(Of TemporaryItemsClass)
    Sub New()
        For I As Integer = 1 To 1000
            TemporaryItems.Add(New TemporaryItemsClass With {
                .Rct = False,
                .CharacterName = "Number" & I
        Next I
        DGEditing.ItemsSource = TemporaryItems
    End Sub
    Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
        Dim row = TryCast(DGEditing.ItemContainerGenerator.ContainerFromIndex(35), DataGridRow)
        Dim cell = TryCast(DGEditing.Columns(0).GetCellContent(row), DataGridCell)
        Dim rectangle = TryCast(cell.Content, Rectangle)
        rectangle.Fill = Brushes.Red
    End Sub
End Class

Below is updated as Pete O'Hanlon said in first comment of solution 1:
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    Dim row = TryCast(DGEditing.ItemContainerGenerator.ContainerFromIndex(35), DataGridRow)
    Dim cell As DataGridCell = GetCell(DGEditing, row, 0)
    Dim rectangle = TryCast(cell.Content, Rectangle)
    rectangle.Fill = Brushes.Red
End Sub
Private Function GetCell(dg As DataGrid, rowContainer As DataGridRow, column As Integer) As DataGridCell
    Dim returner
    If rowContainer IsNot Nothing Then
        Dim presenter = VisualTreeHelper.GetParent(rowContainer)
        Dim cell As DataGridCell = TryCast(dg.Columns(column).GetCellContent(presenter), DataGridCell)
        If cell IsNot Nothing Then returner = cell
    End If
    Return returner
End Function
Updated 13-May-24 9:26am

Something that catches people out when they look at WPF is that they assume that there is a direct parent/child relationship between elements. So, you would think that the cell is the parent of the rectangle, which is not the case. What you need to do is take the parent control (the cell), and use something called the visual tree to find the child content (the rectangle) from the oarent (the cell). What you are looking for is the VisualTreeHelper[^] class
Share this answer
Sh.H. 13-May-24 15:18pm    
@Pete O'Hanlon
Thanks for reply.
I updated as you said.
But the error is there yet.
Kindly please check the main question as I updated.
Pete O'Hanlon 14-May-24 3:05am    
It's not just the cell that sits in the visual tree, it's the rectangle as well. So, once you have the cell, you have to use the visual tree to find the rectangle. Something to remember - your hunt for elements may need to be recursive.
Sh.H. 14-May-24 3:14am    
@ Pete O'Hanlon
Thanks for explanation, but I could not figure out it.
Could you please kindly do me favor and make a sample code, so I understand your idea much better?
Pete O'Hanlon 14-May-24 3:58am    
I'm not a Visual Basic developer so this might not be 100% correct, but you should be able to get the idea.

Public Function FindAncestorByType(Of T As {DependencyObject, New})( _
ByVal dependencyObject As DependencyObject) As T

Dim parent As DependencyObject = VisualTreeHelper.GetParent(dependencyObject)

If parent Is Nothing Then
Return Nothing
End If

Dim convertedParent As T = TryCast(parent, T)

If convertedParent Is Nothing Then
Return FindAncestorByType(Of T)(parent)
End If

Return convertedParent
End Function

Public Function FindDescendantByType(Of T As {DependencyObject, New})( _
ByVal dependencyObject As DependencyObject) As T

Dim child As DependencyObject = VisualTreeHelper.GetChild(dependencyObject)

If child Is Nothing Then
Return Nothing
End If

Dim convertedChild As T = TryCast(child, T)

If convertedChild Is Nothing Then
Return FindDescendantByType(Of T)(child)
End If

Return convertedChild
End Function

Using these calls, you can find the first instance of a particular type using the relevant call. So, if you wanted to find the DataGridCell from a child, you would call GetAncestorByType. To find the Rectangle, from an element higher in the visual tree you would call GetDescendantByType.
Sh.H. 15-May-24 1:06am    
@Pete O'Hanlon
Thanks for the code.
I tried to use it in program, but it is too complicated. And I couldn't find out how can I use it in my own code.
Perhaps, I need to ask you to please kindly make a complete code. I beleive I will understand better and then I can use it in my code. Thank you very very much for this favor and thank you very very much for spending time for this.
Guys! I asked ai to generate a code.
This is its answer:
Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    Dim row As DataGridRow = CType(DGEditing.ItemContainerGenerator.ContainerFromIndex(35), DataGridRow)
    Dim rectangle As Rectangle = FindVisualChild(Of Rectangle)(row)
    rectangle.Fill = Brushes.Red
End Sub

Private Function FindVisualChild(Of T As DependencyObject)(ByVal obj As DependencyObject) As T
    For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(obj) - 1
        Dim child As DependencyObject = VisualTreeHelper.GetChild(obj, i)

        If child IsNot Nothing AndAlso TypeOf child Is T Then
            Return CType(child, T)
            Dim childOfChild As T = FindVisualChild(Of T)(child)

            If childOfChild IsNot Nothing Then
                Return childOfChild
            End If
        End If

    Return Nothing
End Function

But the problem is, after changing color, if I scroll, the red rectangle will change from his place.
And also some other cells also get to red !!!!
Anybody has an idea to correct it?
Share this answer
Richard Deeming 15-May-24 6:44am    
So some code that doesn't work, and doesn't do what you want, is not only "a solution" to your question, it is "THE solution" to your question?!

Remove this non-solution, and update your question instead.
Sh.H. 17-May-24 16:46pm    
@Richard Deeming
Dear Richard. If you read the asnwer, I said it worked. But it has some problems. So I put here to ask anyone if they have any suggestion to improve the code.
Richard Deeming 20-May-24 3:35am    
"It sort-of works but not quite" is NOT the same as "it works".

You have posted a solution which asks for more help. That is not a solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900