Проблема ширины DataGrid RowDetails - PullRequest
13 голосов
/ 18 ноября 2010

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

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

Ответы [ 6 ]

13 голосов
/ 21 октября 2011

Ответы здесь выглядят как обходной путь, поэтому я провел небольшое исследование и нашел решение на форумах Telerik, так как мы используем их RadGridView.Оказалось, что решение работает и для DataGrid.

Ключ в том, чтобы установить для свойства ScrollViewer.Hor HorizontalScrollBarVisibility значение Отключено, см. Пример ниже.Побочным эффектом является то, что если столбцам нужно больше места по горизонтали, чем есть место, они будут обрезаны.Так что, если это проблема, то это решение не оптимально.

13 голосов
/ 18 ноября 2010

Я так и сделал.Я бы лучше использовал для этого свойство в 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;
    }
}
4 голосов
/ 18 мая 2015

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

Спасибо 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>
2 голосов
/ 18 ноября 2010

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

1 голос
/ 16 июня 2011

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

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

...