如何访问数据网格模板列文本框文本 WPF C#

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16997951/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:58:03  来源:igfitidea点击:

How to access datagrid template column textbox text WPF C#

wpfdatagridwpfdatagriddatagridtemplatecolumn

提问by acosta

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 the SelectionChangedevent. Can someone please tell me how to achieve this? I found a similar question herebut it had no answers.

我需要DataGrid从后面的代码访问 a的模板列中的文本,但我不知道如何。我需要将文本更改为我在SelectionChanged事件中传递给它的任何字符串。有人可以告诉我如何实现这一目标吗?我在这里找到了一个类似的问题但没有答案。

回答by Anatoliy Nikolaev

To find a control in a DataGridtemplate column, you should use FindChild():

要在DataGrid模板列中查找控件,您应该使用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:

例如,我在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):

注意:始终只有在控件完全加载时才使用 FindChild,否则将找不到它并返回 null。在这种情况下,我将此代码放在事件ContentRendered(Window) 中,它表示窗口的所有内容都成功加载(即使事件 MyDataGrid_Loaded 也无法访问 MyTextBlock,因为它尚未加载):

    private void Window_ContentRendered(object sender, EventArgs e)
    {
        TextBlock MyTextBlock = FindChild<TextBlock>(MyDataGrid, "MyTextBlock");

        MessageBox.Show(MyTextBlock.Text);
    }

EDIT1:

编辑1:

To access the control of selected row to add event SelectionChangedto DataGridin which to function, which will give a selected row:

要访问选定行的控件以将事件SelectionChanged添加到DataGrid中,在其中起作用,这将给出选定行:

    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():

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:

编辑2:

To get ALLthe items I rewrote the function FindChild():

为了获得所有项目,我重写了函数 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.

通常,这种做法不是最好的……要获取项目(例如全部或选定),您可以直接联系存储数据的列表(例如ObservableCollection)。此外,它是有用的事件,例如PropertyChanged