如何使用ListView
获取GridView
标题的高度?它甚至可能吗?
我需要根据ListView
标题的高度设置一个控件的高度,所以我开始编写Converter
。问题是我无法访问实际高度。
Visual Studio的调试器向我显示GridView
有一个名为HeaderRowPresenter
的属性,该属性又具有属性ActualHeight
。但我无法访问它,HeaderRowPresenter
似乎受到保护或私有。
所有其他ColumnHeader*
属性(ColumnHeaderContainerStyle
,ColumnHeaderTemplate
等)在此对象上为null
,对于{{Header*
属性相同1}}(除了作为标题内容的Columns
之外)。
答案 0 :(得分:0)
好的,我找到了一个解决方案,但我并不为此感到自豪,因为它使用了反射:
我写了Converter
,其中View
和ListView
为值和参数,并返回标题的高度差:
public class HeightSyncConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
GridView gvLocal = value as GridView;
ListView lvOther = parameter as ListView;
if( gvLocal == null || lvOther == null)
{
return 0;
}
GridView gvOther = (GridView)lvOther.View;
try
{
// get the non-public HeaderRowPresenter property
GridViewHeaderRowPresenter hrpLocal = (GridViewHeaderRowPresenter)gvLocal.GetType().GetProperty("HeaderRowPresenter", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(gvLocal);
GridViewHeaderRowPresenter hrpOther = (GridViewHeaderRowPresenter)gvOther.GetType().GetProperty("HeaderRowPresenter", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(gvOther);
if( hrpLocal == null || hrpOther == null )
{
return 0;
}
// Only works if the other ListView's header is higher than the local one's
if( hrpLocal.ActualHeight > hrpOther.ActualHeight )
{
return 0;
}
return hrpOther.ActualHeight - hrpLocal.ActualHeight;
}
catch(TargetInvocationException) { }
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
然后我用它来定义Grid.Row
:
<UserControl x:Class="GUI.ListViewLayout"
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:GUI"
xmlns:conv="clr-namespace:GUI.Converter"
mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"
Loaded="Window_Loaded">
<UserControl.Resources>
<Style x:Key="verticalGridViewColumnHeader" TargetType="GridViewColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" FontWeight="Bold"
VerticalAlignment="Center" TextAlignment="Center" HorizontalAlignment="Center">
<TextBlock.LayoutTransform>
<RotateTransform Angle="270" />
</TextBlock.LayoutTransform>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<conv:HeightSyncConverter x:Key="myConverter" />
</UserControl.Resources>
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition x:Name="fillerRow" Height="{Binding View, ElementName=listView1, Converter={StaticResource myConverter}, ConverterParameter={x:Reference listView2}}" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button x:Name="someControl" Grid.RowSpan="2">Placeholder</Button>
<ListView x:Name="listView1" Grid.Row="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Header 1" Width="60"/>
<GridViewColumn Header="Header 2" Width="60" />
</GridView>
</ListView.View>
</ListView>
<ListView x:Name="listView2" Grid.Row="1" Grid.Column="1" Grid.RowSpan="2">
<ListView.View>
<GridView>
<GridViewColumn Header="Long Header 1"
HeaderContainerStyle="{StaticResource verticalGridViewColumnHeader}" Width="Auto" />
<GridViewColumn Header="Long Header 2"
HeaderContainerStyle="{StaticResource verticalGridViewColumnHeader}" Width="Auto" />
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl>
问题是在ListView
之前调用转换器并初始化它们的标头,因此我重新评估代码隐藏中的Binding
:
public partial class ListViewLayout : UserControl
{
public ListViewLayout()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
BindingExpression binding = fillerRow.GetBindingExpression(RowDefinition.HeightProperty);
binding.UpdateTarget();
}
}
总而言之,我认为这不值得付出努力,最好的方法是自己定义标题的高度,而不是检索自动计算的ActualHeight
。