值不在ObservableCollection< tabitem>中的预期范围内

本文关键字:范围内 tabitem ObservableCollection | 更新日期: 2023-09-27 18:12:33

我使用tabcontrol控件有问题。

我正在使用绑定和转换器来动态地向tabcontrol添加项。

当添加第二个表项时得到以下异常(见下面的代码):值不在预期范围内

其加

:

вMS.Internal.XcpImports。CheckHResult (UInt32人力资源)вMS.Internal.XcpImports。SetValue(IManagedPeerBase obj, DependencyProperty属性,DependencyObject doh)вMS.Internal.XcpImports。SetValue(IManagedPeerBase doh, DependencyProperty属性,Object obj)вSystem.Windows.DependencyObject。SetObjectValueToCore(DependencyProperty dp,对象值)вSystem.Windows.DependencyObject。设置有效值(DependencyProperty)属性;新条目,对象的新值вSystem.Windows.DependencyObject。updateevaluevalue (DependencyProperty)属性,EffectiveValueEntry旧条目,EffectiveValueEntry&newEntry, ValueOperationвSystem.Windows.DependencyObject。SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet)вSystem.Windows.Controls.ContentControl。set_Content(对象值)вSilverlightApplication1.Services.TabConverter。转换(对象值,类型targetType,对象参数,CultureInfo文化)

主页xaml:

<UserControl x:Class="SilverlightApplication1.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         mc:Ignorable="d"
         d:DesignHeight="1024"
         d:DesignWidth="1280"
         xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
         xmlns:local="clr-namespace:SilverlightApplication1.Services">
<UserControl.Resources>
    <local:TabConverter x:Key="tabConverter" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot"
      Background="White">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="1*" />
        <ColumnDefinition Width="4*" />
    </Grid.ColumnDefinitions>
    <ListBox SelectionChanged="ListBox_SelectionChanged">
        <ListBoxItem Content="ViewA"></ListBoxItem>
        <ListBoxItem Content="ViewB"></ListBoxItem>
    </ListBox>
    <sdk:TabControl Grid.Column="1"
                    ItemsSource="{Binding Tabs, Converter={StaticResource tabConverter}}" />
</Grid>

主页后台代码:

    public partial class MainPage : UserControl {
    ViewModel viewModel = new ViewModel();
    public MainPage() {
        InitializeComponent();
        this.DataContext = viewModel;
    }
    private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
        try {
            viewModel.Tabs.Add(new TabItemModel() {
                Header = "New Tab",
                Content = new Grid()
            });
            // sdk:tabcontrol does not listen CollectionChanged of viewModel.Tabs.
            // thats why:
            viewModel.Tabs = viewModel.Tabs;
        } catch (Exception) { }
    }
}
数据模型:

 public class TabItemModel {
    public string Header { get; set; }
    public UIElement Content { get; set; }
}

视图模型:

public class ViewModel:INotifyPropertyChanged {
    ObservableCollection<TabItemModel> tabs = new ObservableCollection<TabItemModel>();
    public ObservableCollection<TabItemModel> Tabs {
        get { return tabs; }
        set { tabs = value; OnPropertyChanged(PropertyNames.Tabs); }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string property) {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
    class PropertyNames {
        public const string Tabs = "Tabs";
    }
}

标签转换器:

public class TabConverter : IValueConverter {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        try {
            var object_data = value as ObservableCollection<TabItemModel>;
            var result = new List<TabItem>();
            foreach (var item in object_data) {
                result.Add(new TabItem() { 
                    Header = item.Header,
                    Content = item.Content // if comment this, everything works
                });
            }
            return result;
        } catch (Exception e) {
            MessageBox.Show(e.StackTrace, e.Message, MessageBoxButton.OK);
            return null;
        }
    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
        throw new NotImplementedException();
    }
}

值不在ObservableCollection< tabitem>中的预期范围内

您的问题是您在数据模型中保留了UIElement

在MVVM中,这本身是一个很大的禁忌,但这里的具体问题是,当您添加第二个TabItemModel和转换器重新创建所有需要的TabItem时,第一个 TabItemModel的内容在一瞬间被放置在两个tabitem上。一个UI元素只能有一个父元素。

这里最"MVVM"的解决方案是将UI元素排除在数据模型之外。相反,只需在TabItemModel.Content中保留一些原始数据,并在xaml中使用DataTemplate s来表示该数据的UI。

如果你需要在你的数据模型中保持UI元素,我建议你看看这个调整的TabControl,它修复了有bug的Silverlight TabControl,不需要转换器正常工作:Silverlight TabControl与数据绑定(从这篇讨论同样问题的SO帖子中获取:绑定一个Silverlight TabControl到一个集合)