How to access datagrid template column textbox text WPF C#
To find a control in a DataGrid
template column, you should use FindChild()
:
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
{
if (parent == null)
{
return null;
}
T foundChild = null;
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
T childType = child as T;
if (childType == null)
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
}
else
if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
else
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null)
{
break;
}
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}
For example I have this template column in MyDataGrid:
<DataGridTemplateColumn Width="1.5*" IsReadOnly="False">
<DataGridTemplateColumn.Header>
<TextBlock Text="Sample" ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}" FontSize="14" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="MyTextBlock" Text="Hello!" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Access it from the code, you can:
TextBlock MyTextBlock = FindChild<TextBlock>(MyDataGrid, "MyTextBlock");
MessageBox.Show(MyTextBlock.Text);
Note: Always use FindChild only when the control will be fully loaded, otherwise it will not find it and give null. In this case, I put this code in the event ContentRendered (Window) which says that all the contents of the window successfully load (even the event MyDataGrid_Loaded not have access to MyTextBlock, because it is not yet loaded):
private void Window_ContentRendered(object sender, EventArgs e)
{
TextBlock MyTextBlock = FindChild<TextBlock>(MyDataGrid, "MyTextBlock");
MessageBox.Show(MyTextBlock.Text);
}
EDIT1:
To access the control of selected row to add event SelectionChanged to DataGrid in which to function, which will give a selected row:
private void MyDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
var row_list = GetDataGridRows(MyDataGrid);
foreach (DataGridRow single_row in row_list)
{
if (single_row.IsSelected == true)
{
TextBlock MyTextBlock = FindChild<TextBlock>(single_row, "MyTextBlock");
MessageBox.Show(MyTextBlock.Text);
}
}
}
catch
{
throw new Exception("Can't get access to DataGridRow");
}
}
Listing of GetDataGridRows():
public IEnumerable<DataGridRow> GetDataGridRows(DataGrid grid)
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource)
{
yield return null;
}
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row)
{
yield return row;
}
}
}
EDIT2:
To get ALL the items I rewrote the function FindChild():
public static void FindChildGroup<T>(DependencyObject parent, string childName, ref List<T> list) where T : DependencyObject
{
// Checks should be made, but preferably one time before calling.
// And here it is assumed that the programmer has taken into
// account all of these conditions and checks are not needed.
//if ((parent == null) || (childName == null) || (<Type T is not inheritable from FrameworkElement>))
//{
// return;
//}
int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childrenCount; i++)
{
// Get the child
var child = VisualTreeHelper.GetChild(parent, i);
// Compare on conformity the type
T child_Test = child as T;
// Not compare - go next
if (child_Test == null)
{
// Go the deep
FindChildGroup<T>(child, childName, ref list);
}
else
{
// If match, then check the name of the item
FrameworkElement child_Element = child_Test as FrameworkElement;
if (child_Element.Name == childName)
{
// Found
list.Add(child_Test);
}
// We are looking for further, perhaps there are
// children with the same name
FindChildGroup<T>(child, childName, ref list);
}
}
return;
}
Calling this new function:
private void Window_ContentRendered(object sender, EventArgs e)
{
// Create the List
List<TextBlock> list = new List<TextBlock>();
// Find all elements
FindChildGroup<TextBlock>(MyDataGrid, "MyTextBlock", ref list);
string text = "";
// Print
foreach (TextBlock elem in list)
{
text += elem.Text + "\n";
}
MessageBox.Show(text, "Text in TextBlock");
}
Generally, this practice is not the best ... to get the items (such as all or selected), you can contact directly to the list which stores your data (like ObservableCollection). Also, it is useful events such as PropertyChanged.
acosta
Updated on June 28, 2022Comments
-
acosta almost 2 years
I need to access the text in a
DataGrid
's template column from code behind, but I don't know how. I need to change the text to whatever string I pass to it on theSelectionChanged
event. Can someone please tell me how to achieve this? I found a similar question here but it had no answers. -
acosta almost 11 yearsI am facing the same problem the person in the thread I linked to. I can't find a way for this to work on every Row. Only one. How to make it work on selected row?
-
acosta almost 11 yearsHmm.. the code for getting all of them works, but the one from the first edit just throws the exception that it can't access the DataGridRow
-
Anatoliy Nikolaev almost 11 yearsI have this exception is triggered when the wrong name of the control, for example: TextBlock MyTextBlock = FindChild<TextBlock>(single_row, "WrongNameOfTextBlock"). And when passed the wrong DataGrid, example NullDataGrid: DataGrid NullDataGrid = null; var row_list = GetDataGridRows(NullDataGrid). Check these cases.
-
nam over 3 years@AnatoliyNikolaev But if you are using
Page
instead ofWindow
?Page
does not seem to haveContentRendered
event.