使用GridView获取ListView的标题高度

时间:2016-08-18 20:15:24

标签: wpf listview gridview

如何使用ListView获取GridView标题的高度?它甚至可能吗?

我需要根据ListView标题的高度设置一个控件的高度,所以我开始编写Converter。问题是我无法访问实际高度。

Visual Studio的调试器向我显示GridView有一个名为HeaderRowPresenter的属性,该属性又具有属性ActualHeight。但我无法访问它,HeaderRowPresenter似乎受到保护或私有。

所有其他ColumnHeader*属性(ColumnHeaderContainerStyleColumnHeaderTemplate等)在此对象上为null,对于{{Header*属性相同1}}(除了作为标题内容的Columns之外)。

顺便说一下:我试图解决一个different problem而我目前的方法让我这样做,所以也许我错误地采取了这种做法。

1 个答案:

答案 0 :(得分:0)

好的,我找到了一个解决方案,但我并不为此感到自豪,因为它使用了反射:

我写了Converter,其中ViewListView为值和参数,并返回标题的高度差:

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