user857521
user857521

Reputation:

Get DataGrid Row from ComboBox Event

I have a DataGrid with 2 columns defined in XAML as

<DataGrid x:Name="marketInfodg" Grid.Row="1"
ItemsSource = "{Binding ElementName=This, Path=dataTableTest}"
CanUserAddRows="False">
<DataGrid.Columns>
    <DataGridComboBoxColumn Header="Department Id" x:Name="comboboxColumn1"
         SelectedValueBinding="{Binding Department Id}" />
        <DataGridTemplateColumn x:Name="DataGridTempCol" Header="Selection">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ComboBox
x:                  Name = "combo"
                    SelectedValue = "{Binding Selection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                    ItemsSource = "{Binding comboBoxSelections, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                    DropDownOpened = "combo_DropDownOpened"
                    DisplayMemberPath = "Key"
                    IsEditable="True">
                    </ComboBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

The constructor code is

_dataTableTest = new DataTable();
DataColumn dc = new DataColumn();
dc.ReadOnly = false;
dc.DataType = typeof(String);
dc.ColumnName = "Department Id";
_dataTableTest.Columns.Add(dc);

DataColumn dc1 = new DataColumn();
dc1.ReadOnly = false;
dc1.DataType = typeof(KeyValuePair<string, double>);
dc1.ColumnName = "Selection";
_dataTableTest.Columns.Add(dc1);

marketInfodg.ItemsSource = _dataTableTest.DefaultView;
var row = _dataTableTest.NewRow();
row = _dataTableTest.NewRow();
_dataTableTest.Rows.Add(row);
row["Department Id"] = "X567";
row["Selection"] = (KeyValuePair<string, double>)comboBoxSelections[0];

which effectively sets a single row as column "Department Id" = "X567" and a second column is a combobox set to the first item in comboBoxSelections[0]

The combo_DropDownOpened event fires when any Combobox drop down is opened (obviously) and I can set the variable cb based on the sender, using

private void combo_DropDownOpened(object sender, EventArgs e)
{
  var cb = ((System.Windows.Controls.ComboBox)sender);
}

How do I also get the associated Row (all columns in the Row) and RowIndex/number of the firing ComboBox in the combo_DropDownOpened event?

Upvotes: 1

Views: 2671

Answers (1)

Rohit Vats
Rohit Vats

Reputation: 81253

ComboBox lies in the visual tree of the DataGrid. If you travel up Visual Tree you will find the DataGridRow on the way to the top to the DataGrid.

You can use the VisualTreeHelper class to walk up to the Visual tree. Generally, you can use this method to find any parent in the Visual tree of your control. Put this method in some Utility class and use whenever you feel like walking up to Visual tree for your control to find any parent -

public static Parent FindParent<Parent>(DependencyObject child)
            where Parent : DependencyObject
{
   DependencyObject parentObject = child;

   //We are not dealing with Visual, so either we need to fnd parent or
   //get Visual to get parent from Parent Heirarchy.
   while (!((parentObject is System.Windows.Media.Visual)
           || (parentObject is System.Windows.Media.Media3D.Visual3D)))
   {
       if (parentObject is Parent || parentObject == null)
       {
           return parentObject as Parent;
       }
       else
       {
          parentObject = (parentObject as FrameworkContentElement).Parent;
       }
    }

    //We have not found parent yet , and we have now visual to work with.
    parentObject = VisualTreeHelper.GetParent(parentObject);

    //check if the parent matches the type we're looking for
    if (parentObject is Parent || parentObject == null)
    {
       return parentObject as Parent;
    }
    else
    {
        //use recursion to proceed with next level
        return FindParent<Parent>(parentObject);
    }
}

Now, in your dropDown event handler you can use the above function to find the DataGridRow like this -

private void combo_DropDownOpened(object sender, EventArgs e)
{
   var cb = ((System.Windows.Controls.ComboBox)sender);
   DataGridRow dataGridRow = FindParent<DataGridRow>(cb);
   int index = dataGridRow.GetIndex();
}

Upvotes: 5

Related Questions