Длина элемента в зависимости от других элементов

Чего я хочу достичь

Я хотел бы создать специальный элемент управления, чтобы иметь возможность отображать заголовок, а некоторые элементы ссылаются на заголовок:

  • Колонка с номером комментария фиксированного размера
  • Столбец с именем (в настоящее время КОММЕНТАРИЙ): нефиксированный размер
  • Столбец с именем (в настоящее время GRAPH XT): фиксированный размер
  • Столбец с именем (в настоящее время Время): фиксированный размер
  • Столбец с именем (в настоящее время видимый): фиксированный размер

Пользователь может изменить размер среды, и только второй столбец должен адаптироваться. Как вы можете видеть на гифке ниже:

через GIPHY

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
93
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Наконец, после закрытия/открытия 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;
    }
}

Другие вопросы по теме