DataGrid RowDetails Проблема ширины

Предположим, у меня есть 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, и не влиять на саму Width?

Вещи, которые я пробовал, которые позволяют получить упаковку, но не дают удовлетворительного результата

  • Установите ширину или максимальную ширину на границе или в текстовом блоке. Не очень динамично.
  • Установите ScrollViewer.HorizontalScrollBarVisibility = "Disabled" в DataGrid. Не очень хорошо, когда столбцы не влезают.

person Fredrik Hedblad    schedule 18.11.2010    source источник


Ответы (6)


Ответы здесь казались обходным решением, поэтому я провел небольшое исследование и нашел решение на форумах 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>

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.

person TGasdf    schedule 21.10.2011
comment
Это решение не масштабируется, когда вам действительно требуется горизонтальная полоса прокрутки для прокрутки до скрытых столбцов! - person Ahmad; 18.05.2015

Это то, чем я закончил. Я бы предпочел использовать для этого свойство в DataGrid, но, поскольку такого свойства не существует, мне понадобился обходной путь.

alt text

Сначала я просто использовал ActualWidth из родительского DataGrid и удалил константу 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 не менялся в зависимости от видимой полосы прокрутки), тем самым устраняя необходимость в 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;
    }
}
person Fredrik Hedblad    schedule 18.11.2010
comment
с вашей обновленной версией с ItemsPresenter в качестве предка вертикальная полоса прокрутки не соблюдается. Я вычитаю 22, чтобы избежать горизонтальной полосы прокрутки. - person user2452157; 29.06.2016

Вот что я в итоге сделал: привязал ширину деталей строки к фактической ширине презентатора, а затем добавил границу различной толщины, чтобы компенсировать наличие / отсутствие вертикальной полосы прокрутки в презентаторе. Этот подход отлично сработал для меня. Пример 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>
person Ahmad    schedule 18.05.2015

Вы могли бы привязать MaxWidth к ElementName=PART_ColumnHeadersPresenter, Path=ActualWidth или, возможно, RenderSize.Width. Я считаю, что это часть шаблона DataGrid, которая отображает столбцы, поэтому теоретически она должна работать.

person Rachel    schedule 18.11.2010
comment
Спасибо за отзыв! Это довольно близко к тому, чем я закончил. - person Fredrik Hedblad; 18.11.2010

Спасибо, Meleak, ваше решение мне понравилось. Одно небольшое дополнение для нас, новичков в WPF. Обязательно объявите свой класс Converter как ресурс, чтобы на него можно было ссылаться в выражении привязки.

Я поместил свой в 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>
person Paul Chavez    schedule 29.12.2010
comment
Спасибо за ответ, я добавил это в свое обновленное решение, которое устранило необходимость в MultiConverter. - person Fredrik Hedblad; 02.01.2011

Чтобы уберечь других от головной боли и времени проб и ошибок:

После возни с последним (01.01.11) решением Фредрика Хедблада в течение некоторого времени я понял, что Значение ConverterParameter должно быть 6 + [левое поле} + [правое поле] (т.е. поля самого внешнего контейнера в шаблоне). После изучения увеличенного снимка экрана я ожидаю, что 6 - ширина вертикальной полосы слева от каждой строки.

person Jim Hansen    schedule 15.06.2011
comment
Будет ли это решение масштабироваться для разных настроек DPI! - person Ahmad; 18.05.2015