将 ItemsControl 绑定到 UserControls 集合时引发异常

发布于 2024-11-29 05:55:44 字数 4510 浏览 1 评论 0原文

在我的应用程序中,模板化表单需要在堆栈面板中显示用户控件列表。我想我可以在表单上使用 ItemsControl 并将其绑定到公开“子用户控件”的集合。当模板化表单加载时,这种方法第一次工作正常,但如果我对子用户控件的 Observable 集合进行任何更改,我会收到异常“值不在预期范围内”。

我浏览了很多帖子,但似乎没有一个解决方案有效。我粘贴了一个示例代码来显示我正在讨论的问题。示例代码有

  1. Mainpage,其中包含 ItemsCOntrol。 Items 控件绑定到 AnyControl 类型的 Observablecollection。

  2. 类 AnyControl 有一个公共属性 AttachedControl。这 AttachedControl 是类型对象。

当主页加载时,我创建 2 个 AnyControl 实例,并将 AttachedControl 属性设置为文本框实例。

主页有 3 个按钮

  1. “显示全部”。它设置主页和两个页面的数据上下文 文本框显示在表单上。
  2. 删除第二个控件。单击此 按钮从 ObservableCollection 中删除第二个条目,并且 第二个文本框消失。
  3. 恢复第二个控制。单击此 按钮将第二个条目添加回可观察集合中。 从逻辑上讲,第二个文本框应该显示在表单上,​​但相反 我得到了例外。

代码从这里开始...... MainPage.xaml.cs

public partial class MainPage : UserControl, INotifyPropertyChanged
{
    public AnyControl control1;
    public AnyControl control2;

    public MainPage()
    {
        InitializeComponent();

        control1 = new AnyControl(new TextBox() { Text = "First Textbox" });
        control2 = new AnyControl(new TextBox() { Text = "Second Textbox" });

        _allVMs = new ObservableCollection<AnyControl>();
        _allVMs.Add(control1);
        _allVMs.Add(control2);
    }       

    private ObservableCollection<AnyControl> _allVMs;
    public ObservableCollection<AnyControl> ActiveViews
    {
        get { return _allVMs;}
        set
        {
            _allVMs = value;
            NotifyPropertyChanged("ActiveViews");
        }
    }

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
        this.LayoutRoot.DataContext = this; // RecordTemplate;
    }

    private void Button2_Click(object sender, RoutedEventArgs e)
    {
        this.ActiveViews.RemoveAt(1);
        NotifyPropertyChanged("ActiveViews");
    }

    private void Button3_Click(object sender, RoutedEventArgs e)
    {
        this.ActiveViews.Add(control2);
        NotifyPropertyChanged("ActiveViews");
    }            

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

AnyControl.cs

public class AnyControl
{
    public object AttachedControl { get; set; }
    public AnyControl(object control)
    {
        AttachedControl = control;
    }
}

MainPage.xaml

<UserControl x:Class="SilverlightApplication2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:layoutPrimitivesToolkit="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:local="clr-namespace:SilverlightApplication2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>           
    </Grid.RowDefinitions>

    <ItemsControl ItemsSource="{Binding ActiveViews}" x:Name="ItemsControl">
        <ItemsControl.ItemsPanel >
            <ItemsPanelTemplate x:Name="a7777">
                <VirtualizingStackPanel Orientation="Vertical" x:Name="222"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding AttachedControl}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <StackPanel Orientation="Horizontal" Grid.Row="1">
    <Button Content="Show All" Height="22" Click="Button1_Click" Margin="5,0,5,0" />
        <Button Content="Remove second control" Height="22" Click="Button2_Click" Margin="5,0,5,0"/>
        <Button Content="Restore second control" Height="22" Click="Button3_Click" Margin="5,0,5,0"/>
    </StackPanel>
</Grid>

非常感谢任何帮助。 谢谢 一个

In my application a templated form needs to show a list of usercontrols in a stackpanel. I figured I could use ItemsControl on the form and bind it to a collection that exposes the "child usercontrols". This approach works fine the first time when the templated form loads but if I make any changes to the Observable collection of child usercontrols, I get an exception "Value does not fall within the expected range".

I have looked thru many posts but none of the solutions seem to have worked. I am pasting a sample code that shows the issue I am talking about. The sample code has

  1. Mainpage with ItemsCOntrol in it. The Itemscontrol is bound to an
    Observablecollection of type AnyControl.

  2. Class AnyControl has a public property AttachedControl. The
    AttachedControl is type object.

When the Mainpage loads, I create 2 instances of AnyControl and set the AttachedControl property to instances of Textboxes.

Mainpage has 3 buttons

  1. Show All. which sets the datacontext of the mainpage and the two
    textboxes show up on the form.
  2. Remove Second Control. clicking this
    button removes second entry from the ObservableCollection and the
    second textbox disappears.
  3. Restore Second Control. clicking this
    button adds the second entry back into the Observable Collection.
    Logically the second textbox should show up on the form but instead
    I get the exception.

The code starts here.....
MainPage.xaml.cs

public partial class MainPage : UserControl, INotifyPropertyChanged
{
    public AnyControl control1;
    public AnyControl control2;

    public MainPage()
    {
        InitializeComponent();

        control1 = new AnyControl(new TextBox() { Text = "First Textbox" });
        control2 = new AnyControl(new TextBox() { Text = "Second Textbox" });

        _allVMs = new ObservableCollection<AnyControl>();
        _allVMs.Add(control1);
        _allVMs.Add(control2);
    }       

    private ObservableCollection<AnyControl> _allVMs;
    public ObservableCollection<AnyControl> ActiveViews
    {
        get { return _allVMs;}
        set
        {
            _allVMs = value;
            NotifyPropertyChanged("ActiveViews");
        }
    }

    private void Button1_Click(object sender, RoutedEventArgs e)
    {
        this.LayoutRoot.DataContext = this; // RecordTemplate;
    }

    private void Button2_Click(object sender, RoutedEventArgs e)
    {
        this.ActiveViews.RemoveAt(1);
        NotifyPropertyChanged("ActiveViews");
    }

    private void Button3_Click(object sender, RoutedEventArgs e)
    {
        this.ActiveViews.Add(control2);
        NotifyPropertyChanged("ActiveViews");
    }            

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

AnyControl.cs

public class AnyControl
{
    public object AttachedControl { get; set; }
    public AnyControl(object control)
    {
        AttachedControl = control;
    }
}

MainPage.xaml

<UserControl x:Class="SilverlightApplication2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" 
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:layoutToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:layoutPrimitivesToolkit="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Layout.Toolkit"
xmlns:local="clr-namespace:SilverlightApplication2"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>           
    </Grid.RowDefinitions>

    <ItemsControl ItemsSource="{Binding ActiveViews}" x:Name="ItemsControl">
        <ItemsControl.ItemsPanel >
            <ItemsPanelTemplate x:Name="a7777">
                <VirtualizingStackPanel Orientation="Vertical" x:Name="222"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ContentPresenter Content="{Binding AttachedControl}"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

    <StackPanel Orientation="Horizontal" Grid.Row="1">
    <Button Content="Show All" Height="22" Click="Button1_Click" Margin="5,0,5,0" />
        <Button Content="Remove second control" Height="22" Click="Button2_Click" Margin="5,0,5,0"/>
        <Button Content="Restore second control" Height="22" Click="Button3_Click" Margin="5,0,5,0"/>
    </StackPanel>
</Grid>

Any Help is much appreciated.
Thanks
A

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

中二柚 2024-12-06 05:55:44

编写了一个自定义控件来解决这个问题。由于我想要的只是在“父”表单中显示用户控件,因此我最终创建了一个自定义面板控件。添加了一个名为 ItemsSource 的依赖属性。此属性的处理程序将其集合中的自定义控件添加到面板的 CHildren 集合中。

@ColinE,我确实确保在将子控件添加到面板之前检查它是否是另一个面板的子控件。如果是,我将获取对其父面板控件的引用,并从该父面板的子集合中删除该控件。

看起来效果很好。

感谢您的评论。
一个

Wrote a custom control to solve this issue. Since all I wanted was to show usercontrols within a "parent" form, I ended up creating a custom panel control. Added a dependency property called ItemsSource to it. The handler for this property adds the custom controls in its collection to the panel's CHildren collection.

@ColinE, I did make sure that before adding a child control to the panel I check if it is child of another panel. If it is I obtain a reference to its parent panel control and remove the control from that parent panel's children collection.

It seems to work just fine.

Thanks for the comments.
A

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文