NotifyCollectionChangedEvent 处理程序中未处理的异常“参数不正确”

Unhandled exception `The parameter is incorrect` in NotifyCollectionChangedEvent handler

我有一个非常简单的 ListView,它的 ItemsSource 是一个 ObservableCollection。最好用代码展示一下:

MainPage.xaml:

<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Windows.UI.Xaml.Shapes"
x:Class="Test.MainPage" Background="Black" >

<Grid x:Name="Board" Background="Transparent" >
    <ListView ItemsSource="{x:Bind LineList}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="local:Line">
                <StackPanel Orientation="Horizontal" Spacing="5">
                    <TextBlock Foreground="White" Text="{x:Bind Name}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

Mainpage.xaml.cs:

public sealed partial class MainPage : Page
{
    public ObservableCollection<Line> LineList = new ObservableCollection<Line>();

    public MainPage()
    {
        InitializeComponent();
        LineList.CollectionChanged += List_CollectionChanged;
        LineList.Add(new Line { Name = "Line1" });
        LineList.Add(new Line { Name = "Line2" });
    }

    private void List_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if(e.Action == NotifyCollectionChangedAction.Add)
        {
            Board.Children.Add(e.NewItems[0] as Line);//if I comment out this line, no exception
        }
    }
}

我真正想要的是,当我在 ListView 上添加一个 Line 以显示它是 Name 时,它也会作为实际的 [=18] 添加到网格中=]. 请注意,我使用 ListView 只是为了显示这些线的名称,而在网格中我想要一个实际的 Line 形状

我不知道我做错了什么,但上面的尝试给出了规定的异常。

如果这些信息有帮助:

  1. 如果我不在 Grid
  2. 中添加 Line,则不会出现异常
  3. 没有例外如果:Board.Children.Add(new Line { Name = "Line2" });

我不确定这是否是您想要的,但就是这样

MainPage.xaml

<Page x:Class="App4.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:App4"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">
    <Page.Resources>
        <Style x:Key="LineViewItemContainerStyle"
               TargetType="ListViewItem">
            <Setter Property="FontFamily"
                    Value="{ThemeResource ContentControlThemeFontFamily}" />
            <Setter Property="FontSize"
                    Value="{ThemeResource ControlContentThemeFontSize}" />
            <Setter Property="Background"
                    Value="{ThemeResource ListViewItemBackground}" />
            <Setter Property="Foreground"
                    Value="{ThemeResource ListViewItemForeground}" />
            <Setter Property="TabNavigation"
                    Value="Local" />
            <Setter Property="IsHoldingEnabled"
                    Value="True" />
            <Setter Property="Padding"
                    Value="0" />
            <Setter Property="HorizontalContentAlignment"
                    Value="Stretch" />
            <Setter Property="VerticalContentAlignment"
                    Value="Stretch" />
            <Setter Property="MinWidth"
                    Value="{ThemeResource ListViewItemMinWidth}" />
            <Setter Property="MinHeight"
                    Value="{ThemeResource ListViewItemMinHeight}" />
            <Setter Property="AllowDrop"
                    Value="False" />
            <Setter Property="UseSystemFocusVisuals"
                    Value="True" />
            <Setter Property="FocusVisualMargin"
                    Value="0" />
            <Setter Property="FocusVisualPrimaryBrush"
                    Value="{ThemeResource ListViewItemFocusVisualPrimaryBrush}" />
            <Setter Property="FocusVisualPrimaryThickness"
                    Value="2" />
            <Setter Property="FocusVisualSecondaryBrush"
                    Value="{ThemeResource ListViewItemFocusVisualSecondaryBrush}" />
            <Setter Property="FocusVisualSecondaryThickness"
                    Value="1" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListViewItem">
                        <ListViewItemPresenter x:Name="Root"
                                               CheckBrush="{ThemeResource ListViewItemCheckBrush}"
                                               ContentMargin="{TemplateBinding Padding}"
                                               CheckBoxBrush="{ThemeResource ListViewItemCheckBoxBrush}"
                                               ContentTransitions="{TemplateBinding ContentTransitions}"
                                               CheckMode="{ThemeResource ListViewItemCheckMode}"
                                               DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
                                               DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
                                               DragBackground="{ThemeResource ListViewItemDragBackground}"
                                               DragForeground="{ThemeResource ListViewItemDragForeground}"
                                               FocusVisualSecondaryBrush="{TemplateBinding FocusVisualSecondaryBrush}"
                                               FocusVisualPrimaryThickness="{TemplateBinding FocusVisualPrimaryThickness}"
                                               FocusVisualSecondaryThickness="{TemplateBinding FocusVisualSecondaryThickness}"
                                               FocusBorderBrush="{ThemeResource ListViewItemFocusBorderBrush}"
                                               FocusVisualMargin="{TemplateBinding FocusVisualMargin}"
                                               FocusVisualPrimaryBrush="{TemplateBinding FocusVisualPrimaryBrush}"
                                               FocusSecondaryBorderBrush="{ThemeResource ListViewItemFocusSecondaryBorderBrush}"
                                               HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                               Control.IsTemplateFocusTarget="True"
                                               PressedBackground="{ThemeResource ListViewItemBackgroundPressed}"
                                               PlaceholderBackground="{ThemeResource ListViewItemPlaceholderBackground}"
                                               PointerOverForeground="{ThemeResource ListViewItemForegroundPointerOver}"
                                               PointerOverBackground="{ThemeResource ListViewItemBackgroundPointerOver}"
                                               ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
                                               SelectedForeground="{ThemeResource ListViewItemForegroundSelected}"
                                               SelectionCheckMarkVisualEnabled="{ThemeResource ListViewItemSelectionCheckMarkVisualEnabled}"
                                               SelectedBackground="{ThemeResource ListViewItemBackgroundSelected}"
                                               SelectedPressedBackground="{ThemeResource ListViewItemBackgroundSelectedPressed}"
                                               SelectedPointerOverBackground="{ThemeResource ListViewItemBackgroundSelectedPointerOver}"
                                               VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />
                                    <VisualState x:Name="Selected" />
                                    <VisualState x:Name="PointerOver">
                                        <VisualState.Setters>
                                            <Setter Target="Root.(RevealBrush.State)"
                                                    Value="PointerOver" />
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="PointerOverSelected">
                                        <VisualState.Setters>
                                            <Setter Target="Root.(RevealBrush.State)"
                                                    Value="PointerOver" />
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="PointerOverPressed">
                                        <VisualState.Setters>
                                            <Setter Target="Root.(RevealBrush.State)"
                                                    Value="Pressed" />
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <VisualState.Setters>
                                            <Setter Target="Root.(RevealBrush.State)"
                                                    Value="Pressed" />
                                        </VisualState.Setters>
                                    </VisualState>
                                    <VisualState x:Name="PressedSelected">
                                        <VisualState.Setters>
                                            <Setter Target="Root.(RevealBrush.State)"
                                                    Value="Pressed" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="DisabledStates">
                                    <VisualState x:Name="Enabled" />
                                    <VisualState x:Name="Disabled">
                                        <VisualState.Setters>
                                            <Setter Target="Root.RevealBorderThickness"
                                                    Value="0" />
                                        </VisualState.Setters>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </ListViewItemPresenter>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Page.Resources>

    <Grid Background="Transparent">
        <ListView ItemContainerStyle="{StaticResource LineViewItemContainerStyle}"
                  ItemsSource="{x:Bind Lines, Mode=OneTime}"
                  HorizontalContentAlignment="Stretch"
                  VerticalContentAlignment="Stretch">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="local:LineViewModel">
                    <Grid x:Name="ItemGrid">
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>
                        <TextBlock Foreground="Black"
                                   Text="{x:Bind Name, Mode=OneWay}" />
                        <Border Grid.Row="1"
                                BorderBrush="Black"
                                BorderThickness="1" />
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Page>

MainPage.xaml.cs

public sealed partial class MainPage : Page
{
    public ObservableCollection<LineViewModel> Lines = new ObservableCollection<LineViewModel>();

    public MainPage()
    {
        InitializeComponent();

        Lines.Add(new LineViewModel { Name = "Line1" });
        Lines.Add(new LineViewModel { Name = "Line2" });
    }
}

public class LineViewModel
{
    public string Name { get; set; }
}

请注意,我没有使用 Line,而是使用了 Border。此外,我需要重写基数 ListViewItemContainerStyle 以将 HorizontalContentAlignmentVerticalContentAlignment 设置为 Stretch,以便 DataTemplate 元素可以占据整个 space ] 项

结果:

我一直在摆弄你的代码,我能够找到你的代码有什么问题。但是我不太确定为什么会这样。

您收到错误的原因是您尝试使用与您的 ListView.ItemsSource 绑定的 UIElement(即 Line)的相同实例.为什么它失败了,对我来说有点神秘。我怀疑禁止 Bind 并将相同的 UIElement 添加到 XAML,因为它可能会创建绑定循环!?不过,这只是一个大胆的猜测。无论如何...

你不应该使用 UIElement 作为绑定上下文——我想不出你会做这样的事情的任何场景。根据我之前的回答(例如 LineViewModel)创建一个单独的模型,并将其用作您的 BindingContext,您会过得更好。您的 MainPage.xaml.cs 代码可能如下所示:

public sealed partial class MainPage : Page
{
    public ObservableCollection<LineViewModel> Lines = new ObservableCollection<LineViewModel>();

    public MainPage()
    {
        InitializeComponent();

        Lines.CollectionChanged += LinesOnCollectionChanged;
        Lines.Add(new LineViewModel { Name = "Line1" });
        Lines.Add(new LineViewModel { Name = "Line2" });
    }

    private void LinesOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            MainGrid.Children.Add(new Line()
            {
                Name = (e.NewItems[0] as LineViewModel)?.Name ?? string.Empty,
                Stroke = new SolidColorBrush(Colors.Black),
                StrokeThickness = 12,
                X1 = 0,
                X2 = 10000
            });
        }
    }
}

public class LineViewModel
{
    public string Name { get; set; }
}

根据我之前的回答MainPage.xaml将保持不变