#c# #.net #wpf #mvvm #datagrid
#c# #.net #wpf #mvvm #datagrid
Вопрос:
В моей Windows.Ресурсы У меня определен следующий столбец:
<DataGridTextColumn x:Key="CustomColumn" x:Shared="False">
<DataGridTextColumn.Header>
<StackPanel>
<Label Padding="0" Name="labelA"/>
<Separator HorizontalAlignment="Stretch"/>
<Label Padding="0" Name="labelB"/>
</StackPanel>
</DataGridTextColumn.Header>
</DataGridTextColumn>
У меня есть событие, которое запускается из моей ViewModel и добавляет следующий «CustomColumn» в мою DataGrid:
var column = FindResource("CustomColumn") as DataGridTextColumn;
var label = FindName("labelA") as Label;
label.Content = string.Format("A {0}", i);
DataGrid1.Columns.Add(column);
Вопрос в том, как бы мне изменить содержимое двух меток внутри заголовка CustomColumn? Приведенный выше код завершается с ошибкой, поскольку он не может найти «labelA». (добавление столбца работает, но мне также нужно установить эти метки). Я предполагаю, что мне нужно найти его через VisualTree — но я хочу убедиться, что я больше ничего не делаю неправильно.
Спасибо за помощь.
Ответ №1:
Я создал несколько помощников по визуальному дереву, которые я постоянно использую для поиска объектов в визуальном дереве
Например, вы можете найти метку с именем «LabelA» с помощью этого:
VisualTreeHelpers.FindChild<Label>(column, "LabelA");
Вот FindChild
метод на случай, если приведенная выше ссылка не работает
using System.Windows;
using System.Windows.Media;
namespace MyNamespace
{
public class VisualTreeHelpers
{
/// <summary>
/// Looks for a child control within a parent by name
/// </summary>
public static T FindChild<T>(DependencyObject parent, string childName)
where T : DependencyObject
{
// Confirm parent and childName are valid.
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);
// If the child is not of the request child type child
T childType = child as T;
if (childType == null)
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
// If the child's name is set for search
if (frameworkElement != null amp;amp;amp;amp; frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
else
{
// recursively drill down the tree
foundChild = FindChild<T>(child, childName);
// If the child is found, break so we do not overwrite the found child.
if (foundChild != null) break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}
}
Комментарии:
1. Спасибо, Рейчел. Я попробую это и расскажу вам, как это работает. — Я просто не был уверен, было ли это из-за визуального дерева или нет. Для моей ситуации является ли приведенное выше решение наилучшим способом?
2. @iimpact Просто перечитайте ваш вопрос, и нет, динамическое добавление новых столбцов в вашу DataGrid не сработает (если только вы не добавляете только один столбец). Причина в том, что вы повторно используете единственный экземпляр вашего
DataGridTextColumn
. Если вы попытаетесь добавить вторую копию этого единственного экземпляра, у вас будет два столбца, которые содержат точно такой же заголовок и данные, потому что вы ссылаетесь на точно такой же экземпляр столбца. Чтобы динамически добавлять столбцы в DataGrid, вам нужно создавать новыйDataGridTextColumn
каждый раз, когда вам нужен новый столбец.3. Хорошо, большое спасибо. Я понимаю, как создавать текстовые столбцы программно, но как будет выполнен пользовательский заголовок?
4. @iimpact Вы можете присвоить
HeaderTemplate
свойству столбца значениеDataTemplate
, существующее в вашем XAML. Я полагаю, что вы также можете установитьHeader
само свойство, но имейте в виду, что если заголовок содержит что-либо иное, кроме строки, то вам придется заново создавать новые экземпляры UIElements заголовка каждый раз, когда вы добавляете новый столбец, поскольку вы не используете шаблон