【问题标题】:Dynamically resize datagrid columns when rows are collapsed行折叠时动态调整数据网格列的大小
【发布时间】:2018-09-26 06:52:32
【问题描述】:

我有一个 DataGrid 控件 dgChangesMade,ItemsSource = ObservableCollection<CheckinPath>

第一列dgPath是一个DataGridTemplateColumn,由

组成
  • 复选框
  • 文本块。转换器为后者返回相对路径。 数据网格行的可见性绑定到 IsVisible 属性。

除了 DataGrid 控件,我还有一个 CheckBox 控件:

  • IsChecked 事件绑定到布尔属性 IsChecked。 setter 设置绑定到 DataGrid 的项目源的对象的 IsVisible 属性。因此,当复选框被(取消)选中时,数据网格行将折叠/显示。
  • SourceUpdated 事件绑定到 CheckBox_SourceUpdated

就像斯科特在another thread 中指出的那样:

DataGrid 将增加列大小以适应数据的变化 更长,但它不会自动减小列大小时 数据长度减少

所以在 CheckBox_SourceUpdated 事件中我

  1. 将列宽设置为 0
  2. 强制更新 DataGrid 布局
  3. 将列宽设置为自动

不幸的是,这没有帮助。 当(取消)选中复选框控件时,列宽会在需要时增加(参见屏幕截图中的 2),但不会根据数据网格列中数据的长度自动减小(参见屏幕截图中的 3,3 显示与1).

有什么想法吗?

截图

XAML

<DataGrid Name='dgChangesMade' Width='Auto' ItemsSource="{Binding Path=ChangesMade}">
    <DataGrid.Resources>
        <DataGridTemplateColumn Width='Auto' x:Key='dgPath' Header='Path' IsReadOnly='True' x:Shared='False'>
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <StackPanel Orientation='Horizontal' VerticalAlignment='Center'>
                    <CheckBox IsChecked='{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}'>
                    <TextBlock Text='{Binding Converter={StaticResource CheckinPathConverter}, ConverterParameter="Path"}' />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <Style x:Key='dgShowHideRow' TargetType='DataGridRow'>
            <Setter Property='Visibility' Value='{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter="Collapsed", Mode=TwoWay}' />
        </Style>

    <DataGrid.Columns>
        <StaticResource ResourceKey='dgPath' />
        <StaticResource ResourceKey='dgStatus' />
        <StaticResource ResourceKey='dgLock' />
    </DataGrid.Columns>
    <DataGrid.ItemContainerStyle>
        <StaticResource ResourceKey='dgShowHideRow' />
    </DataGrid.ItemContainerStyle>
</DataGrid>
<!-- Setter of this checkbox sets the IsVisible property of the datagrid bound objects -->
<CheckBox IsChecked='{Binding IsChecked, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}' SourceUpdated='CheckBox_SourceUpdated'/>

背后的代码

private void CheckBox_SourceUpdated(object sender, DataTransferEventArgs e)
{
    foreach (var c in dgChangesMade.Columns)
        c.Width = 0;

    dgChangesMade.UpdateLayout();
    foreach (var c in dgChangesMade.Columns)
        c.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
}

型号

public class CheckinPath : ViewModelBase
{
    private bool _isVisible;
    public bool IsVisible
    {
        get { return _isVisible; }
        set
        {
            if (_isVisible != value)
            {
                _isVisible = value;
                RaisePropertyChanged(nameof(IsVisible));
            }
        }
    }  
}

【问题讨论】:

  • 您可以尝试强制整个数据网格重新读取数据。将 ChangesMade 设置为 null,然后返回过滤的集合。可能会奏效。可能不会,我必须自己试一试,看看发生了什么。假设该属性引发了 propertychanged。
  • 或者在ChangesMade的collectionview上调用.refresh()。
  • @Andy 我不认为清除数据网格中的所有数据是过滤数据网格的好习惯。与此同时,我自己解决了这个问题。

标签: c# wpf xaml datagrid


【解决方案1】:

我解决了这个问题。

  1. 不再将数据网格项目源绑定到ObservableCollection,而是现在绑定到CollectionView。 这样,可以使用CollectionViewSource Filter 属性显示/隐藏数据网格中的行。 过滤发生在 ViewModel 中。
  2. CollectionView 被过滤后,数据网格的列宽被重置。 因为数据网格是一个控件,所以重置发生在视图后面的代码中(使用来自MVVM Light Toolkit 的 Messenger)

XAML

<DataGrid x:Name='dg'
            ItemsSource='{Binding ChangesMadeView}'
            AutoGenerateColumns='False'
            IsReadOnly='True' .../>
<CheckBox IsChecked='{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}' .../>

窗口代码

public partial class TestWindow : Window
{
    public static readonly Guid Token = new Guid();
    public TestWindow()
    {
        InitializeComponent();
        Messenger.Default.Register<NotificationMessage>(this, Token, ResetColumnWidth);
    }

    private void ResetColumnWidth(NotificationMessage notMessage)
    {
        if (notMessage.Notification == "ResetColumnWidth")
        {
            foreach (DataGridColumn c in dg.Columns)
            {
                c.Width = 0;
                c.Width = DataGridLength.Auto;
            }
        }
    }
}

视图模型

private IList<CheckinPath> _changesMade = new List<CheckinPath>();
public ICollectionView ChangesMadeView { get; private set; }

public TestViewModel()
{
    LoadData(); //Loads data for _changesMade
    ChangesMadeView = CollectionViewSource.GetDefaultView(_changesMade);
}

private bool _isChecked;

public bool IsChecked
{
    get { return _isChecked; }
    set
    {
        if (_isChecked != value)
        {
            _isChecked = value;
            RaisePropertyChanged(nameof(IsChecked));
            ChangesMadeView.Filter = checkinPath => { //do logic for filtering. Returns true or false ;};
            Messenger.Default.Send(new NotificationMessage("ResetColumnWidth"), TestWindow.Token); //notify the code behind of the view
        };
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-22
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 2017-08-04
    • 2020-09-13
    相关资源
    最近更新 更多