我要实现的目标
我想创建特定的控件以能够显示标题,并且一些元素链接到标题:
用户可以调整环境的大小,并且仅第二列必须适应。正如您在下面的gif中看到的:
(通过将所有columDefinition宽度设置为固定大小来创建gif)
问题
所有列必须与其他项目对齐(如gif所示)。每列的大小必须完全相同,并由内容较大的项目确定。在下图中,您可以看到我面临的问题。内容未对齐,因此无法调整列的大小。
我目前拥有的
我尝试以MVVM精神进行设计
我使用ItemsControl来显示有关ItemsSource出价的数据。要修改数据模板,我正在使用DataTemplate。 但是现在,我想访问每个项目的网格(位于“ CommentsListItemControl”中)以测量其列长,最后将最大长度应用于所有列。
我重写了CommentsListItemControl的“ load”事件,但是我无法让父级拥有所有的CommentsListItemControl项目。 然后,我重写CommentsListControl的ItemsControl的“ load”事件,但是我无法获取其容器(然后检查所有子项)。 我正在使用此资源来帮助我: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>
答案 0 :(得分:0)
最后关闭/打开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;
}
}