【问题标题】:Value does not fall within the expected range in ObservableCollection<TabItems>值不在 ObservableCollection<TabItems> 中的预期范围内
【发布时间】:2013-05-06 20:21:59
【问题描述】:

我对 tabcontrol 控件有疑问。

我正在使用绑定和转换器将项目动态添加到 tabcontrol。

添加第二个 tabitem 时出现以下异常(参见下面的代码): 值不在预期范围内

它的堆栈跟踪:

в 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.SetEffectiveValue(DependencyProperty 属性, EffectiveValueEntry& newEntry, Object newValue) в System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty 属性,EffectiveValueEntry oldEntry,EffectiveValueEntry&newEntry,ValueOperation 操作) в System.Windows.DependencyObject.SetValueInternal(DependencyProperty dp, Object value, Boolean allowReadOnlySet) в System.Windows.Controls.ContentControl.set_Content(对象值) в SilverlightApplication1.Services.TabConverter.Convert(Object value, Type targetType, Object parameter, CultureInfoculture)

主页 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();
    }
}

【问题讨论】:

  • +1 用于发布工作代码,这对我来说只是一个简单的复制粘贴 :) 一个小时后我放弃了,因为它只是不工作。海事组织这是一个有缺陷的控制。看看@Sphinxxx 的回答,我想你可以在链接 Silverlight TabControl with data binding 中使用

标签: c# silverlight mvvm converter tabcontrol


【解决方案1】:

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

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

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

如果您确实需要在数据模型中保留 UI 元素,我建议您看看这个经过调整的 TabControl,它修复了有缺陷的 Silverlight TabControl,并且不需要转换器即可正常工作: Silverlight TabControl with data binding(取自这篇讨论相同问题的 SO 帖子:Bind a Silverlight TabControl to a Collection)

【讨论】:

  • 刚刚检查了这个问题,发现 ItemTemplate 属性没有像 Silverlight sdk TabControl 的预期那样工作。
  • @Silvermind:是的,显然是这样。我在答案中发布的两个链接解决了这个确切的问题(尽管我自己没有尝试过 vorrtex 的调整 TabControl)。
  • 我看到 SelectedItem 的一个问题在同一个人的更新文章中得到了解决:vortexwolf.wordpress.com/2011/07/27/… 看起来这对于 OP 的需求来说是一个很好的控制。
  • @DhavalPatel:希望对您有所帮助。如果是,请考虑接受答案:)
猜你喜欢
  • 2011-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多