【问题标题】:DataGridCheckBoxColumn usage -- throws an Unhandled exceptionDataGridCheckBoxColumn 用法——抛出未处理的异常
【发布时间】:2020-05-22 12:07:24
【问题描述】:

当 DataGridCheckBoxColumn 在 DataGrid 中使用并绑定到支持模型中的布尔属性时会发生这种情况。当单击该列并且选中/取消选中复选框时——它的行为符合预期——但是当我关闭主窗口时,抛出异常。当仅使用文本列并与之交互时,不会发生这种情况。如果我根本不与复选框列交互而只是关闭窗口,它也不会发生。只有在与复选框列交互后关闭窗口时才会发生这种情况。

开发环境:

操作系统:
1. Arch Linux,Gnome 3,Wayland。
2.Windows 10 专业版

开发:
dotnet 核心 3.1.103
IDE:VS 代码

重现步骤:

教程文章中提到了使用 DataGrid 的一般过程: Avalonia DataGrid Getting Started

我对本文所做的唯一更改是将 DataGridCheckBoxColumn 添加到 DataGrid 并将布尔值 IsChecked 属性添加到教程中使用的“Person”模型类 - 然后将两者绑定在一起。

所以关键步骤是:

  1. $ dotnet new avalonia.mvvm
  2. 在 *csproj 文件中,将所有 Avalonia 的版本包括到 0.9.10,因为这就是我正在使用的 DataGrid 的版本。
  3. $ dotnet add package Avalonia.Controls.DataGrid
  4. 在 App.xaml 中,添加样式:
    <StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Default.xaml"/>
  5. 将以下属性添加到模型类“Person” --- 其余代码保持不变,按照链接教程:
 public bool IsChecked
        {get;set;}
  1. 将 DataGridCheckBoxColumn 添加到 DataGrid 并将其绑定,如下所示(其余列保持不变,按照链接教程):
<DataGrid.Columns>
        <DataGridTextColumn Header="First Name" 
                            Binding="{Binding FirstName}" 
                            Width="2*" />
        <DataGridTextColumn Header="Last Name" 
                            Binding="{Binding LastName}" 
                            Width="2*" />
        <DataGridTextColumn Header="Department" 
                            Binding="{Binding DepartmentNumber}" 
                            Width="*" />

        <DataGridCheckBoxColumn Header="IsChecked" 
                            Binding="{Binding IsChecked}" 
                            Width="*" />

    </DataGrid.Columns>
  1. 然后,当我运行应用程序(从命令行或 vscode)时——GUI 会按预期显示——包含所有列和值——并且通常会显示额外的复选框列。 __ 当我单击复选框列时 - 复选框确实按预期被选中和取消选中(尽管需要额外单击一次)。 但是当我通过点击右上角的“X”关闭窗口时——这就是未处理的异常发生的时候——而不是在那之前。

完整的异常文本:

未处理的异常。 System.InvalidOperationException:集合已修改;枚举操作可能无法执行。 在 System.Collections.Generic.List`1.Enumerator.MoveNextRare() 在 Avalonia.Collections.AvaloniaList`1.Enumerator.MoveNext() 在 System.Linq.Enumerable.OfTypeIterator[TResult](IEnumerable 源)+MoveNext() 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Visual.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Input.InputElement.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.Control.OnDetachedFromVisualTreeCore(VisualTreeAttachmentEventArgs e) 在 Avalonia.Controls.TopLevel.HandleClosed() 在 Avalonia.Controls.WindowBase.HandleClosed() 在 Avalonia.Controls.Window.HandleClosed() 在 Avalonia.X11.X11Window.Cleanup() 在 Avalonia.X11.X11Window.Dispose() 在 Avalonia.X11.X11Window.OnEventSync(XEvent ev) 在 Avalonia.X11.X11Window.OnEvent(XEvent ev) 在 Avalonia.X11.X11PlatformThreading.HandleX11(CancellationToken cancelToken) 在 Avalonia.X11.X11PlatformThreading.RunLoop(CancellationToken cancelToken) 在 Avalonia.Threading.Dispatcher.MainLoop(CancellationToken cancelToken) 在 Avalonia.Controls.ApplicationLifetimes.ClassicDesktopStyleApplicationLifetime.Start(String[] args) 在 Avalonia.ClassicDesktopStyleApplicationLifetimeExtensions.StartWithClassicDesktopLifetime[T](T builder, String[] args, ShutdownMode shutdownMode) 在 /home/[myusername]/[pathtoproject]/Program.cs:line 14 中的 d3.Program.Main(String[] args)

Person类的代码:

public class Person
    {
        public int DepartmentNumber { get; set; }

        public string DeskLocation{ get; set; }

        public int EmployeeNumber { get; set; }

        public string FirstName { get; set; }

        public string LastName { get; set; }

        public bool IsChecked
        {get;set;}
    }

MainWindowViewModel 的代码,它充当 MainWindow 的代码,并使用上面的 Person 类来托管 ObservableCollection 并将其公开为名为 People 的公共属性。 DataGrid 绑定到这个作为 Person 类集合的 People 属性(谁的属性由不同的列表示,例如 DataGridTextColumn 和 DataGridCheckBoxColumn):

public class MainWindowViewModel : ViewModelBase
    {
        public ObservableCollection<Person> People { get; set;}

        public MainWindowViewModel()
        {
            People = new ObservableCollection<Person>(GenerateMockPeopleTable());
        }

        private ObservableCollection<Person> GenerateMockPeopleTable()
        {
            var defaultPeople = new ObservableCollection<Person>()
            {
                new Person()
                {
                    FirstName = "Pat", 
                    LastName = "Patterson", 
                    EmployeeNumber = 1010,
                    DepartmentNumber = 100, 
                    DeskLocation = "B3F3R5T7",
                    IsChecked = false
                },
                new Person()
                {
                    FirstName = "Jean", 
                    LastName = "Jones", 
                    EmployeeNumber = 973,
                    DepartmentNumber = 200, 
                    DeskLocation = "B1F1R2T3",
                    IsChecked = true
                },
                new Person()
                {
                    FirstName = "Terry", 
                    LastName = "Tompson", 
                    EmployeeNumber = 300,
                    DepartmentNumber = 100, 
                    DeskLocation = "B3F2R10T1",
                    IsChecked = false
                }
            };

            return defaultPeople;
        }
    }

更新:我已经放弃寻找解决方案。这是我的解决方法:

而不是使用 DataGridCheckBoxColumn(它还有一个额外的烦恼,即只有在单击两次时才会被检查——我正在使用 DataGridTemplateColumn。它解决了上述异常问题——以及我想要的被检查属性单击。

<DataGridTemplateColumn Header="Select Todo">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsChecked}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

【问题讨论】:

    标签: c# xaml datagrid avaloniaui avalonia


    【解决方案1】:

    我认为您的问题与您使用的收藏有关,而不是您的复选框。 您必须在收集后致电.ToList()。 请检查以下链接: Collection was modified; enumeration operation may not execute

    【讨论】:

    • 如果它与基础集合有关,那么为什么它只发生在 DataGridCheckBoxColumn 而不是 DataGridTextColumn ?两者都使用相同的基础集合。请查看帖子中的详细信息。
    • 编辑帖子以将代码添加到末尾。
    • 请在编辑复选框列后尝试更改所选行并检查是否抛出异常
    【解决方案2】:

    GenerateMockPeopleTable() 替换为GenerateMockPeopleTable().ToList() 并检查问题是否已解决。

    【讨论】:

    • ObservabeCollection 没有 ToList() 方法。所以我用整个文件中的 List 替换了 Observable 集合本身。现在哪里有 ObservableCollection,哪里就有一个 List,问题仍然存在。如果您查看原始帖子中异常的堆栈跟踪,则该问题源自 Avalonia 的 UI 控件集合中的某个位置,而不是我的集合。我认为 Avalonia 的开发人员需要参与其中。
    • 也许吧。通常我在尝试修改循环内的集合时遇到此错误。
    猜你喜欢
    • 2011-10-10
    • 2013-06-08
    • 1970-01-01
    • 1970-01-01
    • 2016-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-08
    相关资源
    最近更新 更多