DataGrid RowDetails 宽度问题

发布于 2024-10-03 05:35:58 字数 1338 浏览 0 评论 0原文

假设我有一个像这样定义的 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

alt text

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

我尝试过实现换行,但没有以令人满意的方式

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

Suppose I have a DataGrid that is defined like this

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

And looks like this with and without RowDetails

alt text

In the picture to the right I get a very long DataGridRow that never wraps.
Is it possible to get the RowDetails to use the same width as the DataGrid and not effect the Width itself?

Things I have tried that achieves wrapping but not in a satisfying way

  • Set Width or MaxWidth on the Border or the TextBlock. Not very dynamic.
  • Set ScrollViewer.HorizontalScrollBarVisibility="Disabled" on the DataGrid. Not very good when the columns doesn't fit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

哆啦不做梦 2024-10-10 05:35:58

这里的答案感觉像是一个解决方法,所以我做了一些研究,并在 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>

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

The answers here felt like a workaround so I did some research and did find the solution on the Telerik forums, since we use their RadGridView. Turned out the solution worked for DataGrid as well.

The key is to set the ScrollViewer.HorizontalScrollBarVisibility property to Disabled, see example below.

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

Edit:
A side effect is that if the columns needs more space horizontally than there are room for they will be clipped. So if this is a problem then this solution isn't optimal.

内心激荡 2024-10-10 05:35:58

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

alt text

首先,我只是使用父 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;
    }
}

更新

我对解决方案进行了一些改进,对 ItemsPresenter 使用 ActualWidth 而不是 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>

减去常数转换器

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

This is what I ended up doing. I'd rather use a Property on the DataGrid for this but since no such Property exist I needed a workaround.

alt text

First I just used ActualWidth from the parent DataGrid and removed a constant of 9. This worked at first but failed when the vertical scrollbar became visible so I had to use a 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>

And in the converter I used another constant (16) to compensate for a visible vertical scrollbar (if it's visible).

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

Update

I improved on the solution a bit, using ActualWidth for the ItemsPresenter rather then DataGrid (where ActualWidth didn't change depending on a visible ScrollBar), thus removing the need for a MultiConverter and two constants.

<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;
    }
}
婴鹅 2024-10-10 05:35:58

这就是我最终要做的:将行详细信息宽度绑定到其呈现器的实际宽度,然后添加具有不同厚度的边框以补偿呈现器中存在/不存在垂直滚动条。这种方法对我来说非常有效。示例 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>

This is what I ended up doing: binding of the row details width to the actual width of its presenter and then added a border with a varied thickness to compensate for the presence/absence of a vertical scroll-bar in the presenter. This approach worked perfectly for me. Sample 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>
一身仙ぐ女味 2024-10-10 05:35:58

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

You might be able to bind the MaxWidth to ElementName=PART_ColumnHeadersPresenter, Path=ActualWidth or perhaps RenderSize.Width. I believe that is the part of the DataGrid Template that displays the columns so in theory it should work

若相惜即相离 2024-10-10 05:35:58

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

Thanks Meleak, your solution worked well for me. One small addition for us WPF newbies. Be sure to declare your Converter class as a resource so it can be referenced in the Binding expression.

I put mine in App.Xaml like this:

<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>
很糊涂小朋友 2024-10-10 05:35:58

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

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

To save other folks some head scratching and trial-and-error time:

After fussing with Fredrik Hedblad's most recent (1/1/11) solution for some time I figured out that the ConverterParameter value should be 6 + [left margin} + [right margin] (i.e. margins of the outermost container in the template.) After examining a blowup of a screen shot, I expect the 6 is the width of the vertical bar at the left of each row.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文