Чего я хочу достичь
Я хотел бы создать специальный элемент управления, чтобы иметь возможность отображать заголовок, а некоторые элементы ссылаются на заголовок:
Пользователь может изменить размер среды, и только второй столбец должен адаптироваться. Как вы можете видеть на гифке ниже:
(The gif was created by setting all the columDefinition width to a fixed size)Проблема
Все столбцы должны быть выровнены с другим элементом (как на картинке). Размер каждого столбца должен быть одинаковым и определяется элементом с большим содержимым. На изображении ниже вы можете увидеть проблему, с которой я столкнулся. Содержимое не выровнено, и я не могу изменить размер столбца.

Что у меня есть на данный момент
Я стараюсь проектировать в духе MVVM
Я использую ItemsControl для отображения данных по времени ожидания ItemsSource. Чтобы изменить шаблон данных, я использую DataTemplate. Но теперь я хотел бы получить доступ к сетке каждого элемента (который находится в «CommentsListItemControl»), чтобы измерить длину их столбца и, наконец, применить наибольшую длину ко всему столбцу.
Я переопределяю событие «загрузить» элемента управления CommentListItemControl, но не могу заставить родительский элемент иметь все элементы элемента управления CommentListItemControl. Затем я переопределяю событие «загрузить» ItemsControl элемента управления CommentListControl, но не могу получить их контейнер (а затем проверить все дочерние элементы). Я использовал этот ресурс, чтобы помочь мне: https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-find-datatemplate-generated-elements
var items = (ItemsControl)grid.Children[0];
items.ItemContainerGenerator.StatusChanged += (sss,eee) => {
var it = items.ItemContainerGenerator.ContainerFromItem(items.Items[0]);
// Here I check if it was an item i was looking for but no
;
} ;
И код, который я придумал выше (не работает)
Вопрос
Как я могу получить сетку "" через ItemsControl? Ищу уже больше 10 часов... Достаточно ли ясно и полно мое объяснение?
Код ниже
<UserControl x:Class = "CCTT.CommentsListControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:CCTT"
xmlns:design = "clr-namespace:CCTT.ViewModels"
mc:Ignorable = "d"
d:DesignHeight = "450" d:DesignWidth = "800">
<Grid DataContext = "{x:Static design:CommentsListDesignModel.Instance}" >
<ItemsControl ItemsSource = "{Binding Items}">
<ItemsControl.ItemTemplate >
<DataTemplate>
<local:CommentsListItemControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
<UserControl x:Class = "CCTT.CommentsListItemControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:CCTT"
xmlns:design = "clr-namespace:CCTT.ViewModels"
mc:Ignorable = "d"
d:DesignHeight = "100" d:DesignWidth = "600">
<UserControl.Resources>
<local:ListItemTypeToVisibilityValueConverter x:Key = "ListItemTypeToVisibilityValueConverter"/>
<local:TimeToStringValueConverter x:Key = "TimeToStringValueConverter"/>
</UserControl.Resources>
<Grid d:DataContext = "{x:Static design:CommentsListItemDesignModel.Header}" Background = "AliceBlue" VerticalAlignment = "Center" >
<!-- Header -->
<Grid Visibility = "{Binding ItemType, Converter = {StaticResource ListItemTypeToVisibilityValueConverter}, ConverterParameter=Header}">
<Grid.ColumnDefinitions>
<!-- Number of comment -->
<ColumnDefinition Width = "Auto"/>
<!-- Comment -->
<ColumnDefinition Width = "*"/>
<!-- Graph name -->
<ColumnDefinition Width = "Auto"/>
<!-- Time -->
<ColumnDefinition Width = "Auto"/>
<!-- Visibility -->
<ColumnDefinition Width = "Auto"/>
</Grid.ColumnDefinitions>
<!-- Number of comment -->
<TextBlock Grid.Column = "0" Text = "#" Margin = "10" HorizontalAlignment = "Center"/>
<!-- Comment -->
<TextBlock Grid.Column = "1" Text = "{Binding Comment}" HorizontalAlignment = "Left" TextWrapping = "Wrap" Margin = "30,10"/>
<!-- Graph name -->
<TextBlock Grid.Column = "2" Text = "{Binding GraphName}" HorizontalAlignment = "Left" Margin = "10"/>
<!-- Time -->
<TextBlock Grid.Column = "3" Text = "{Binding TimeText}" HorizontalAlignment = "Left" Margin = "30,10"/>
<!-- Visibility -->
<TextBlock Grid.Column = "4" Text = "{Binding VisibilityText}" HorizontalAlignment = "Center" Margin = "30,10"/>
</Grid>
<!-- Item -->
<Grid Visibility = "{Binding ItemType, Converter = {StaticResource ListItemTypeToVisibilityValueConverter}, ConverterParameter=Normal}">
<Grid.ColumnDefinitions>
<!-- Number of comment -->
<ColumnDefinition Width = "Auto"/>
<!-- Comment -->
<ColumnDefinition Width = "*"/>
<!-- Graph name -->
<ColumnDefinition Width = "Auto"/>
<!-- Time -->
<ColumnDefinition Width = "Auto"/>
<!-- Visibility -->
<ColumnDefinition Width = "Auto"/>
</Grid.ColumnDefinitions>
<!-- Number of comment -->
<TextBlock Grid.Column = "0" Text = "{Binding Index}" Margin = "10" HorizontalAlignment = "Center"/>
<!-- Comment -->
<TextBlock Grid.Column = "1" Text = "{Binding Comment}" HorizontalAlignment = "Left" TextWrapping = "Wrap" Margin = "30,10"/>
<!-- Graph name -->
<TextBlock Grid.Column = "2" Text = "{Binding GraphName}" HorizontalAlignment = "Left" Margin = "10"/>
<!-- Time -->
<TextBlock Grid.Column = "3" Text = "{Binding Time, Converter = {StaticResource TimeToStringValueConverter}, ConverterParameter=d/MM/yyyy HH:mm}" HorizontalAlignment = "Left" Margin = "30,10"/>
<!-- Visibility -->
<CheckBox Grid.Column = "4" IsChecked = "{Binding IsVisible}" HorizontalAlignment = "Center" VerticalAlignment = "Center" Margin = "30,10"/>
</Grid>
</Grid>





Наконец, после закрытия/открытия VS он начинает работать...
Вот реальный код, если кому-то нужно:
Логика взаимодействия
/// <summary>
/// Take care of displaying correctly a list of <see cref = "CommentsListItemControl"/> by changing their size if needed
/// </summary>
/// <param name = "sender">And ItemsControl</param>
/// <param name = "e"> A routed event</param>
private void ItemsControl_Loaded(object sender, System.Windows.RoutedEventArgs e)
{
// Get the maximum grid colum size.
List<double> maxSizeColumn = GetGridColumnSize(sender as ItemsControl, "Main_CommentsListItemControl_DO_NOT_CHANGE");
if (maxSizeColumn == null)
return;
//initialize the list
List<GridLength> gridLengths = new List<GridLength>(new GridLength[maxSizeColumn.Count]);
for (int i = 0; i < maxSizeColumn.Count; i++)
{
if (i == 1)
// Let the user be able to resize the content
gridLengths[i] = new GridLength(1, GridUnitType.Star);
gridLengths[i] = new GridLength(maxSizeColumn[i]);
}
SetColumSize(sender as ItemsControl, "Main_CommentsListItemControl_DO_NOT_CHANGE", gridLengths);
}
/// <summary>
/// Search all the column width for the specific control <see cref = "CommentsListItemControl"/>
/// </summary>
/// <param name = "control">An itemsControl with <see cref = "CommentsListItemControl"/>datatemplate</param>
/// <param name = "containerName">The name of the main container of the <see cref = "CommentsListItemControl"/></param>
/// <returns>The maximum width of all columnDefinition inside the control</returns>
private List<double> GetGridColumnSize(ItemsControl control, string containerName)
{
if (control == null)
throw new ArgumentNullException(nameof(control));
List<double> gridSize = null;
// Check the width for each item inside de control
for (int i = 0; i < control.Items.Count; i++)
{
// get the container
var itemControlItem = control.ItemContainerGenerator.ContainerFromIndex(i);
if (itemControlItem == null)
// if the container is not already loaded, return
return null;
// get the main grid
Grid mainGrid = UIHelpers.FindChild<Grid>(itemControlItem, containerName);
//Get the child grid only if visible
var childrenGrid = (((Grid)mainGrid.Children[0]).Visibility == Visibility.Visible) ? (Grid)mainGrid.Children[0] : (Grid)mainGrid.Children[1];
//initialize the list
if (gridSize == null)
gridSize = new List<double>(new double[childrenGrid.ColumnDefinitions.Count]);
//Get the size of every column
for (int j = 0; j < childrenGrid.ColumnDefinitions.Count; j++)
{
// find the size of the grid and if bigger than the previous one, record it
gridSize[j] = Math.Max(gridSize[j], childrenGrid.ColumnDefinitions[j].ActualWidth);
}
}
return gridSize;
}
/// <summary>
/// Set the column width of a <see cref = "ItemsControl"/>
/// </summary>
/// <param name = "control">The control where the column width must be applied</param>
/// <param name = "containerName">The name of the main container of the <see cref = "CommentsListItemControl"/></param>
/// <param name = "gridLengths">The <see cref = "GridLength"/> to be set</param>
private void SetColumSize(ItemsControl control, string containerName, List<GridLength> gridLengths)
{
for (int i = 0; i < control.Items.Count; i++)
{
// get the container
var itemControlItem = control.ItemContainerGenerator.ContainerFromIndex(i);
if (itemControlItem == null)
{
// if the container is not found, inform the user and return
Debugger.Break();
return;
}
// get the main grid
Grid mainGrid = UIHelpers.FindChild<Grid>(itemControlItem, containerName);
//Get the child grid only if visible
var childrenGrid = (((Grid)mainGrid.Children[0]).Visibility == Visibility.Visible) ? (Grid)mainGrid.Children[0] : (Grid)mainGrid.Children[1];
//Check if size are consistent
if (childrenGrid.ColumnDefinitions.Count != gridLengths.Count)
{
// do nothing and inform the user
Debugger.Break();
return;
}
//Apply the size for every column
for (int j = 0; j < childrenGrid.ColumnDefinitions.Count; j++)
{
// find the size of the grid and if bigger than the previous one, record it
if (j == 1)
continue;
childrenGrid.ColumnDefinitions[j].Width = gridLengths[j];
}
}
}
}
Связанный XAML
<UserControl x:Class = "CCTT.CommentsListControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:CCTT"
xmlns:design = "clr-namespace:CCTT.ViewModels"
mc:Ignorable = "d"
d:DesignHeight = "450" d:DesignWidth = "800">
<Grid DataContext = "{x:Static design:CommentsListDesignModel.Instance}" >
<ItemsControl ItemsSource = "{Binding Items}" Loaded = "ItemsControl_Loaded">
<ItemsControl.ItemTemplate >
<DataTemplate>
<local:CommentsListItemControl />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Помощник
public static class UIHelpers
{
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name = "parent">A direct parent of the queried item.</param>
/// <typeparam name = "T">The type of the queried item.</typeparam>
/// <param name = "childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
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 && frameworkElement.Name == childName)
{
// if the child's name is of the request name
foundChild = (T)child;
break;
}
}
else
{
// child element found.
foundChild = (T)child;
break;
}
}
return foundChild;
}
}