0

I use this code to add a TextBox to a DataGrid cell: (no, I can't use XAML here)

Binding binding = new Binding("Fld_Company");
binding.Mode = BindingMode.OneWay;

FrameworkElementFactory frameworkElementFactory = new FrameworkElementFactory(typeof(TextBox));
DataTemplate dataTemplate = new DataTemplate();
dataTemplate.VisualTree = frameworkElementFactory;
frameworkElementFactory.SetBinding(TextBox.TextProperty, binding);

DataGridTemplateColumn dataGridTemplateColumn = new DataGridTemplateColumn();
dataGridTemplateColumn.IsReadOnly = true;
dataGridTemplateColumn.Header = "Company";
dataGridTemplateColumn.CellTemplate = dataTemplate;

this.dataGrid.Columns.Add(dataGridTemplateColumn);

I there a way to get the underlying TextBox control without XAML?

What I tried:

  • VisualTreeHelper, but the GetChildrenCount() is always 0
  • FindName, but I haven't found a proper FrameworkElement
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52

1 Answers1

0

After explored the DataGrid for a while I see that my question does not make any sense. My code above prepares just the DataGrid but does not fill any data. Until that no rows are generated and therefore no underlying TextBox controls can be found.

When the DataGrid gets finally filled with data, the best way to get the underlying controls seems to be catching the LoadinRow event. But when this event fires, the loading of the row is not finished. There needs to be temporarily assigned a second event which fires when the row is finally loaded.

{
    DataGrid.LoadingRow += DataGrid_LoadingRow;
}

private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    // The visual tree is not built until the row is "loaded". This event fires when this happend:
    e.Row.Loaded += DataGrid_Row_Loaded;
}

private void DataGrid_Row_Loaded(object sender, RoutedEventArgs e)
{
    DataGridRow dataGridRow = (DataGridRow)sender;
    // important: Remove the event again
    dataGridRow.Loaded -= DataGrid_Row_Loaded;

    NestedGridFieldProperty ngrProp = (NestedGridFieldProperty)dataGridRow.Item;

    // Get the "presenter", which contains the cells
    DataGridCellsPresenter presenter = coNeboTools.ConeboMisc.GetVisualChild<DataGridCellsPresenter>(dataGridRow);

    // Get the cells in the presenter
    var cells = GetVisualChildren<DataGridCell>(presenter);

    // Get the underlying TextBox in column 0
    TextBox underlyingTextBox = (TextBox)cells.ElementAt(0).Content;

    // the Item property of the row contains the row data
    var myData = dataGridRow.Item;

    // do what ever is needed with the TextBlock
    underlyingTextBox.Foreground = Brushes.Red;
}

    // Static helper method to handle the visual tree
    public static IEnumerable<T> GetVisualChildren<T>(DependencyObject dependencyObject)
           where T : DependencyObject
    {
        if (dependencyObject != null)
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(dependencyObject);

            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(dependencyObject, i);
                if (child != null && child is T)
                {
                    yield return (T)child;
                }

                foreach (T childOfChild in GetVisualChildren<T>(child))
                {
                    yield return childOfChild;
                }
            }
        }
    }

    // Static helper method to handle the visual tree
    public static childItem GetVisualChild<childItem>(DependencyObject obj)
        where childItem : DependencyObject
    {
        foreach (childItem child in GetVisualChildren<childItem>(obj))
        {
            return child;
        }

        return null;
    }
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52