开发者

Exception thrown when binding ItemsControl to a UserControls collection

开发者 https://www.devze.com 2023-03-28 07:06 出处:网络
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 usercontrol

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>
        </ItemsContr开发者_运维知识库ol.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


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

0

精彩评论

暂无评论...
验证码 换一张
取 消