简体   繁体   English

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

[英]Unhandled exception `The parameter is incorrect` in NotifyCollectionChangedEvent handler

I have a very simple ListView whose ItemsSource is a ObservableCollection . 我有一个非常简单的ListView它的ItemsSource是一个ObservableCollection Better show it with code: 用代码更好地显示它:

MainPage.xaml: 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: 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
        }
    }
}

What I actually want is that, when I add a Line on the ListView to show it's Name , it be also added in the Grid as an actual Shape . 我真正想要的是,当我在ListView上添加一条Line以显示其Name ,也将它作为实际Shape添加到Grid中。 Note that, I am using the ListView only to show the Names of those Lines, and in the Grid I want an actual Line Shape 请注意,我仅使用ListView来显示这些线的名称,并且在网格中我想要一个实际的Line

I don't know what I've done wrong, but the above attempt gives the stated Exception. 我不知道我做错了什么,但是上面的尝试给出了所述的异常。

If these informations help: 如果这些信息有帮助:

  1. No Exception occurs if I don't add the Line in the Grid 如果我不在Grid添加Line ,则不会发生异常
  2. No Exception if : Board.Children.Add(new Line { Name = "Line2" }); 如果出现以下情况, Board.Children.Add(new Line { Name = "Line2" });例外: Board.Children.Add(new Line { Name = "Line2" });

I've been fiddling around with your code and I was able to track down what is wrong with your code. 我一直在摆弄您的代码,并且能够找到您的代码出了什么问题。 However I'm not really sure why it's happening. 但是我不太确定为什么会这样。

The reason why you're getting errors is because you're trying to use same instance of an UIElement (ie Line ) that you're binding to your ListView.ItemsSource . 出现错误的原因是因为您试图使用绑定到ListView.ItemsSourceUIElement实例(即Line )。 Why it's failing, is a bit of mystery to me. 为什么失败了,这对我来说还是个谜。 I suspect that it's forbidden to Bind and add the same UIElement to XAML, as it might create binding loops!? 我怀疑禁止Bind并将相同的UIElement添加到XAML,因为它可能会创建绑定循环! That's just a wild guess though. 不过,这只是一个疯狂的猜测。 Anyways... 无论如何...

You shouldn't be using UIElement as the binding context - I can't think of any scenario that you would do such thing. 您不应该将UIElement用作绑定上下文-我想不出您会做这种事情的任何情况。 You will be better off by creating a separate model, as per my previous answer (eg LineViewModel ), and using that as your BindingContext . 按照我之前的回答(例如LineViewModel )创建一个单独的模型,并将其用作BindingContext ,您会更好。 Your MainPage.xaml.cs code could look like this: 您的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; }
}

The MainPage.xaml will stay the same, as per my previous answer 根据我之前的回答, MainPage.xaml将保持不变

I'm not sure if this is what you're after but here it goes 我不确定这是否是您要的东西,但是事情就这样了

MainPage.xaml 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 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; }
}

Note, that instead of using Line I used Border . 注意,我没有使用Line而是使用Border Also, I needed to override base ListViewItemContainerStyle to set HorizontalContentAlignment and VerticalContentAlignment to Stretch , so that the DataTemplate elements can take up the entire space of the item 另外,我需要重写基本ListViewItemContainerStyle来将HorizontalContentAlignmentVerticalContentAlignment设置为Stretch ,以便DataTemplate元素可以占用项目的整个空间

The result: 结果:

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM