【问题标题】:Exception thrown when binding ItemsControl to a UserControls collection将 ItemsControl 绑定到 UserControls 集合时引发异常
【发布时间】:2011-08-12 20:05:13
【问题描述】:

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

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

  1. 包含 ItemsCONtrol 的主页。 Itemscontrol 绑定到一个 AnyControl 类型的 Observablecollection。

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

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

主页有 3 个按钮

  1. 显示全部。它设置了主页的数据上下文和两个 文本框显示在表单上。
  2. 删除第二个控件。点击这个 按钮从 ObservableCollection 和 第二个文本框消失。
  3. 恢复第二个控制。点击这个 按钮将第二个条目添加回 Observable Collection。 从逻辑上讲,第二个文本框应该显示在表单上,​​而是 我得到了例外。

代码从这里开始..... 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>

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

【问题讨论】:

  • 请提供异常详情
  • 它抛出“值不在预期范围内。”例外。
  • 您正在做的事情很奇怪,试图将 UIElements 的实例视为您正在做的数据,而理论上可能会给您带来痛苦。你为什么做这个?在我看来,更好的方法是将实际数据绑定到 ContentDataTemplateContentTemplate
  • 您好 AnthonyWJones,我正在使用 MVVM 模式的 ViewModelFirst 方法,其中 ViewModel 决定显示哪个视图。这不是一种非常常见的方法,但当您的视图是 ChildWindows 时非常有用。
  • “值不在预期范围内”通常表明您的代码导致 UIElement 多次放置在可视化树中,因此它有多个父级,这是无效的。我建议遵循@AnthonyWJones 的建议

标签: .net silverlight exception user-controls itemscontrol


【解决方案1】:

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

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

它似乎工作得很好。

感谢 cmets。 一个

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-10-11
    • 2010-12-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多