【问题标题】:DataGrid RowDetails Width problemDataGrid RowDetails 宽度问题
【发布时间】:2011-05-11 18:17:36
【问题描述】:

假设我有一个这样定义的 DataGrid

<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>

无论有没有 RowDetails,看起来都是这样

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

我尝试过的实现包装但不令人满意的方法

  • 在边框或文本块上设置宽度或最大宽度。不是很有活力。
  • 在 DataGrid 上设置 ScrollViewer.Horizo​​ntalScrollBarVisibility="Disabled"。当列不适合时不是很好。

【问题讨论】:

    标签: wpf datagrid wpfdatagrid rowdetails


    【解决方案1】:

    这里的答案感觉像是一种解决方法,所以我做了一些研究,并在 Telerik 论坛上找到了解决方案,因为我们使用了他们的 RadGridView。结果证明该解决方案也适用于 DataGrid。

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

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

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

    【讨论】:

    • 当您实际需要水平 ScrollBar 以滚动到隐藏列时,此解决方案无法扩展!
    【解决方案2】:

    这就是我最终要做的。我宁愿为此使用 DataGrid 上的属性,但由于不存在这样的属性,我需要一种解决方法。

    首先,我只使用了父 DataGrid 中的 ActualWidth 并删除了一个常量 9。这最初是有效的,但是当垂直滚动条变得可见时失败了,所以我不得不使用 MultiBinding。

    <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;
        }
    }
    

    更新

    我对解决方案进行了一些改进,将 ActualWidth 用于 ItemsPresenter 而不是 DataGrid(其中 ActualWidth 不会根据可见的 ScrollBar 而改变),因此不再需要 MultiConverter 和两个常量。

    <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>
    

    SubtractConstantConverter

    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;
        }
    }
    

    【讨论】:

    • 以 ItemsPresenter 作为祖先的更新版本不尊重垂直滚动条。我减去 22 以避免水平滚动条。
    【解决方案3】:

    这就是我最终做的事情:将行详细信息宽度绑定到其演示者的实际宽度,然后添加一个具有不同厚度的边框以补偿演示者中垂直滚动条的存在/不存在。这种方法对我来说非常有效。示例 xml:

    <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】:

      您也许可以将 MaxWidth 绑定到 ElementName=PART_ColumnHeadersPresenter, Path=ActualWidth 或 RenderSize.Width。我相信这是显示列的 DataGrid 模板的一部分,所以理论上它应该可以工作

      【讨论】:

      • 感谢您的提示!这与我最终所做的非常接近。
      【解决方案5】:

      感谢Meleak,您的解决方案对我来说效果很好。我们 WPF 新手的一个小补充。请务必将您的 Converter 类声明为资源,以便可以在 Binding 表达式中引用它。

      我像这样将我的放在 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>
      

      【讨论】:

      • 感谢您的回复,我已将此添加到更新的解决方案中,从而不再需要 MultiConverter。
      【解决方案6】:

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

      在对 Fredrik Hedblad 的最新 (1/1/11) solution 大惊小怪一段时间后,我发现 ConverterParameter 值应该是 6 + [left margin} + [右边距] (即模板中最外层容器的边距。)在检查屏幕截图的放大后,我预计 6 是左侧垂直条的宽度每一行。

      【讨论】:

      • 此解决方案能否针对不同的 DPI 设置进行扩展!
      猜你喜欢
      • 2011-10-17
      • 1970-01-01
      • 2011-10-24
      • 1970-01-01
      • 2013-05-12
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多