首页 > 解决方案 > 其他项目功能中的项目长度

问题描述

我想要达到的目标

我想创建特定的控件,以便能够显示标题和一些链接到标题的元素:

用户可以调整环境大小,只有第二列必须适应。正如您在下面的 gif 中看到的:

通过 GIPHY

(gif是通过将所有columDefinition宽度设置为固定大小来创建的)

问题

所有列必须与其他项目对齐(如 gif 中所示)。每列的大小必须完全相同,由内容较大的项目决定。在下图中,您可以看到我面临的问题。内容未对齐,我无法调整列的大小。 在此处输入图像描述

我目前拥有的

我尝试用 MVVM 精神进行设计

我使用 ItemsControl 来显示 ItemsSource 出价的数据。要修改数据的模板,我使用的是 DataTemplate。但是现在,我想访问每个项目的网格(在“CommentsListItemControl”中)来测量它们的列长度,最后将最大长度应用于所有列。

我覆盖了 CommentsListItemControl 的“加载”事件,但我无法让父级拥有所有 CommentsListItemControl 项目。然后我覆盖 CommentsListControl 的 ItemsControl 的“加载”事件,但我无法获取他们的容器(然后检查所有子项)。我正在使用此资源来帮助我: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>

标签: wpf

解决方案


最后在关闭/打开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;
    }
}

推荐阅读