代码之家  ›  专栏  ›  技术社区  ›  Fredrik Hedblad

数据网格行详细信息宽度问题

  •  12
  • Fredrik Hedblad  · 技术社区  · 14 年前

    假设我有一个这样定义的数据网格

    <DataGrid AreRowDetailsFrozen="True"
              ItemsSource="{Binding MyCollection}"
              AutoGenerateColumns="False">
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <Border CornerRadius="5" BorderBrush="Red"
                        BorderThickness="2" Background="Black">
                    <TextBlock Foreground="White" Text="{Binding RowDetails}"
                               TextWrapping="Wrap"/>
                </Border>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
        <DataGrid.Columns>
            <DataGridTextColumn Header="0" Binding="{Binding Value1}"/>
            <DataGridTextColumn Header="1" Binding="{Binding Value2}"/>
            <DataGridTextColumn Header="2" Binding="{Binding Value3}"/>
            <DataGridTextColumn Header="3" Binding="{Binding Value4}"/>
        </DataGrid.Columns>
    </DataGrid>
    

    不管有没有行细节

    alt text

    在右边的图片中,我得到一个很长的DataGridRow,它从不换行。
    是否可以让RowDetails使用与DataGrid相同的宽度,而不影响宽度本身?

    我尝试过的包装方法,但并不令人满意

    • 在边框或文本块上设置宽度或最大宽度。不是很有活力。
    • 在数据网格上设置ScrollViewer.HorizontalScrollBarVisibility=“Disabled”。当柱子不合适的时候就不太好了。
    6 回复  |  直到 13 年前
        1
  •  13
  •   Fredrik Hedblad    14 年前

    这就是我最后所做的。我宁愿在DATAGRID上使用这个属性,但由于没有这样的属性,所以我需要一个解决方案。

    alt text

    首先,我使用了父数据网格中的ActualWidth并删除了一个9的常量。一开始这很有效,但当垂直滚动条变为可见时失败了,所以我不得不使用多重绑定。

    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <Border HorizontalAlignment="Left" CornerRadius="5"
                    BorderBrush="Red" BorderThickness="2" Background="Black">
                <Border.Width>
                    <MultiBinding Converter="{StaticResource RowDetailsWidthMultiConverter}"
                                  ConverterParameter="9">
                        <Binding RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}"
                                 Path="ActualWidth"/>
                        <Binding RelativeSource="{RelativeSource AncestorType={x:Type ScrollViewer}}"
                                 Path="ComputedVerticalScrollBarVisibility"/>
                    </MultiBinding>
                </Border.Width>
                <TextBlock Foreground="White" Text="{Binding RowDetails}" TextWrapping="Wrap"/>
            </Border>
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
    

    在转换器中,我使用另一个常量(16)来补偿可见的垂直滚动条(如果它是可见的)。

    public class RowDetailsWidthMultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double originalWidth = (double)values[0];
            Visibility verticalScrollbarVisibility = (Visibility)values[1];
            double subtractWidth = System.Convert.ToDouble(parameter);
            double returnWidth = originalWidth - subtractWidth;
            if (verticalScrollbarVisibility == Visibility.Visible)
            {
                return returnWidth - 16;
            }
            return returnWidth;
        }
        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }
    

    更新

    我对解决方案做了一些改进,对ItemsPresenter使用ActualWidth,而不是DataGrid(其中ActualWidth不随可见滚动条的变化而变化),这样就不需要多个转换器和两个常量。

    <DataGrid.Resources>
        <local:SubtractConstantConverter x:Key="SubtractConstantConverter"/>
    </DataGrid.Resources>
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <Border HorizontalAlignment="Left" CornerRadius="5"
                    BorderBrush="Red" BorderThickness="2" Background="Black"
                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsPresenter}},
                                    Path=ActualWidth,
                                    Converter={StaticResource SubtractConstantConverter},
                                    ConverterParameter=6}">
                <TextBlock Foreground="White" Text="{Binding RowDetails}" TextWrapping="Wrap"/>
            </Border>
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
    

    减常量转换器

    public class SubtractConstantConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double originalValue = (double)value;
            double subtractValue = System.Convert.ToDouble(parameter);
            return originalValue - subtractValue;
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }
    
        2
  •  13
  •   TGasdf    13 年前

    这里的答案就像是一个解决办法,所以我做了一些研究,并在Telerik论坛上找到了解决方案,因为我们使用了他们的RadGridView。结果发现这个解决方案也适用于DataGrid。

    关键是将ScrollViewer.HorizontalScrollBarVisibility属性设置为Disabled,请参见下面的示例。

    <DataGrid ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <DataGrid.RowDetailsTemplate>
        <DataTemplate>
            <Border>
                <TextBlock Foreground="White" Text="{Binding RowDetails}"
                           TextWrapping="Wrap"/>
            </Border>
        </DataTemplate>
    </DataGrid.RowDetailsTemplate>
    

    编辑: 一个副作用是,如果柱在水平方向上需要的空间大于它们被剪裁的空间。所以如果这是个问题,那么这个解决方案就不是最优的。

        3
  •  4
  •   Ahmad    9 年前

    这就是我最终所做的:将行详细信息宽度绑定到演示者的实际宽度,然后添加一个具有不同厚度的边框,以补偿演示者中是否存在垂直滚动条。这种方法对我很有效。样品xaml:

    <DataGrid.RowDetailsTemplate>
         <DataTemplate>
            <Border BorderThickness="2,2,8,2"
                    Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsPresenter}}, Path=ActualWidth}"
                    HorizontalAlignment="Left" >
               <!-- add the row details view contents here -->
             </Border>
         </DataTemplate>
    </DataGrid.RowDetailsTemplate>
    
        4
  •  2
  •   Rachel    14 年前

    你可以将MaxWidth绑定到 ElementName=PART_ColumnHeadersPresenter, Path=ActualWidth 或者是RenderSize.Width。我相信这是DataGrid模板中显示列的部分,因此在理论上应该可以工作

        5
  •  2
  •   Community CDub    7 年前

    谢谢 Meleak ,你的解决方案对我很有效。我们WPF新手的一小部分。请确保将转换器类声明为资源,以便可以在绑定表达式中引用它。

    我把我的放在App.Xaml中,如下所示:

    <Application x:Class="ISCBilling.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:conv="clr-namespace:my.application.namespace"
                 StartupUri="IscBillingWindow.xaml">
        <Application.Resources>
    
            <conv:RowDetailsWidthMultiConverter x:Key="RowDetailsWidthMultiConverter" />
    
        </Application.Resources>
    </Application>
    
        6
  •  1
  •   Community CDub    7 年前

    为了节省其他人的一些挠头和试错时间:

    在和弗雷德里克·赫布拉德最近的一次(2011年1月1日)争吵之后 solution 有一段时间我发现 转换器参数 价值应该是 6+[左边距}+[右边距] (即模板中最外层容器的边距)检查屏幕快照的放大后,我预计 6个 是每行左侧垂直条的宽度。