【问题标题】:Maintain column widths of a DataGrid when a grouping option changes分组选项更改时保持 DataGrid 的列宽
【发布时间】:2018-03-24 07:43:56
【问题描述】:

我一直在使用Rubberduck 来改进我的 VBA 代码。鸭子向我介绍了单元测试和许多其他适当的技术。出于感激,我试图回馈并为我发现的问题提供解决方案,尽管我不懂 C#。

该问题涉及System.Windows.Controls.Grid。网格可以选择按结果或所在模块对测试结果进行分组。如果调整列宽,然后更改分组,则不会反映宽度变化。

我在视图模型上创建了我认为允许两种方式绑定的属性,如下所示。

private DataGridLength _outcomeColumnWidth;
public DataGridLength OutcomeColumnWidth
{
    get => _outcomeColumnWidth;
    set
    {
        _outcomeColumnWidth = value;
        OnPropertyChanged();
    } 
}

我已经编辑了 XAML,试图创建一个 TwoWay 绑定,该绑定将在更改分组后保持更改的列宽。

<Grid>
    <controls:GroupingGrid ItemsSource="{Binding Source={StaticResource ResultsByOutcome}}"
                                SelectedItem="{Binding SelectedTest}"
                                ShowGroupingItemCount="True"
                                Visibility="{Binding IsChecked, ElementName=GroupByOutcome, Converter={StaticResource BoolToVisibility}}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Outcome}">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate DataType="unitTesting:TestMethod">
                        <Image Source="{Binding Result.Outcome, Converter={StaticResource OutcomeIconConverter}}" Height="16" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_QualifiedModuleName}" Binding="{Binding Declaration.QualifiedName.QualifiedModuleName}"
                                Width="{Binding OutcomeColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_MethodName}" Binding="{Binding Declaration.IdentifierName}"
                                Width="{Binding ModuleColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Message}" Binding="{Binding Result.Output}"
                                Width="{Binding MessageColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Duration}" Binding="{Binding Result.Duration, StringFormat={}{0}ms}" 
                                Width="{Binding DurationColumnWidth, Mode=TwoWay}"/>
        </DataGrid.Columns>
    </controls:GroupingGrid>
    <controls:GroupingGrid ItemsSource="{Binding Source={StaticResource ResultsByModule}}"
                                SelectedItem="{Binding SelectedTest}"
                                ShowGroupingItemCount="True"
                                Visibility="{Binding IsChecked, ElementName=GroupByLocation, Converter={StaticResource BoolToVisibility}}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Outcome}">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate DataType="unitTesting:TestMethod">
                        <Image Source="{Binding Result.Outcome, Converter={StaticResource OutcomeIconConverter}}" Height="16" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_QualifiedModuleName}" Binding="{Binding Declaration.QualifiedName.QualifiedModuleName}" 
                                Width="{Binding OutcomeColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_MethodName}" Binding="{Binding Declaration.QualifiedName.MemberName}" 
                                Width="{Binding ModuleColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Message}" Binding="{Binding Result.Output}"
                                Width="{Binding MessageColumnWidth, Mode=TwoWay}"/>
            <DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=TestExplorer_Duration}" Binding="{Binding Result.Duration, StringFormat={}{0}ms}"
                                Width="{Binding DurationColumnWidth, Mode=TwoWay}"/>
        </DataGrid.Columns>
    </controls:GroupingGrid>
</Grid>

视图模型继承自一个抽象类ViewModelBase,它实现了INotifyPropertyChanged。抽象类也有public event PropertyChangedEventHandler PropertyChanged 和方法OnPropertyChanged。我已经在 getset 上为该属性设置了断点,但都没有到达。

【问题讨论】:

    标签: c# data-binding wpf-controls


    【解决方案1】:

    DataGrid 列不是逻辑树或可视树的一部分,因为它们是抽象对象,因此它们无权访问 ViewModel 的 DataContext。这使得它们很难绑定。好消息是,您可以通过多种方式做到这一点。

    代理对象

    <UserControl.Resources>
        <FrameworkElement x:Key="ProxyElement" DataContext="{Binding}" />
    </UserControl.Resources>
    
    <Grid>
        <DataGrid ItemsSource="{Binding Descriptions}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Description"
                                    Width="{Binding Source={StaticResource ProxyElement}, Path=Width, Mode=TwoWay}"
                                    Binding="{Binding Description}" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
    

    为了进一步阅读,我建议查看https://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/,因为它很好地概述了原因,并使用他创建的特定 ProxyClass 提供了上述代码的替代方案。

    【讨论】:

    • 我添加了一个 ProxyClass,它公开了列宽的成员。在第一次加载时,宽度设置为public DataGridLength Header1Width { get; set; } = 250;,并且GroupingGrids 的列宽度相同。当列的宽度发生变化并且显示第二个网格时,宽度尚未更新。我可以更新第二个网格的宽度,并且两者都单独保存。就像每个字段都有一个不同的字段,我不知道如何让两者都查看一个字段。
    猜你喜欢
    • 2012-07-14
    • 2010-12-29
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 2019-01-26
    • 1970-01-01
    相关资源
    最近更新 更多