使用 MVVM 将新项目添加到 TabControl ItemSsource 时选择最后一个 TabItem

Posted

技术标签:

【中文标题】使用 MVVM 将新项目添加到 TabControl ItemSsource 时选择最后一个 TabItem【英文标题】:Selecting the last TabItem when new items are added to a TabControl's ItemSource using MVVM 【发布时间】:2021-10-11 10:46:37 【问题描述】:

我通过将ItemsSource 绑定到MyUnicornsViewModel 创建了一个动态生成的TabControl

随着新项目被添加到MyUnicornsViewModel... 新标签项目被创建。但是,TabControl 中不会自动选择新添加的选项卡。

如何在添加新标签时选择它们?

<TabControl ItemsSource="Binding MyUnicornsViewModel" SelectedItem="Binding SelectedItem">
    <TabControl.ItemTemplate>
        <!-- header template -->
        <DataTemplate>
            <TextBlock Text="Binding Name" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate>
        <!-- body template-->
        <DataTemplate>
            <TextBlock Text="Binding Content" />
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

起初,我希望TabControl 中有“ItemsChanged”或“ItemAdded”事件,这样我可以在添加新项目时在代码隐藏中设置 SelectedIndex。

我尝试的另一件事是将TabControl.SelectedItem 绑定到MyUnicornsViewModel 中的SelectedItem 属性。可悲的是,这也不起作用。

MyUnicornsViewModel:

public class MyUnicornsViewModel : ObservableCollection<UnicornViewModel>

    ...

    private void AddNewUnicorn()
    
        var awesomeUnicorn = new UnicornViewModel();
        Add(awesomeUnicorn);
        SelectedItem = awesomeUnicorn;  //I expected my TabControl to have 'awesomeUnicorn' selected.
    

    public UnicornViewModel SelectedItem  get; set; 

【问题讨论】:

【参考方案1】:

这里有几个问题:

    ObservableCollection 派生“视图模型”非常奇怪。视图模型应该包含一个可观察的集合。 视图模型需要实现INotifyPropertyChanged接口;从提供的代码中不清楚UnicornViewModel 是否实现了这个接口,但是MyUnicornsViewModel 绝对没有。

以下是一些建议:

    实现INotifyPropertyChanged 接口的视图模型基类将真正帮助您完成大部分工作。您可以使用 INotifyPropertyChanged documentation 编写自己的代码,或者寻找适合您项目的 MVVM 框架(例如 Prism、MVVM Light、ReactiveUI)。其中每一个都将提供一个用于视图模型的基类 - BindableBaseViewModelBaseReactiveObject,分别用于上述每个框架。 MyUnicornsViewModel 应该有: 一个ObservableCollection,用于收集独角兽;这将绑定到您的TabControl 上的ItemsSource 属性。 SelectedItem 属性在设置时必须触发 PropertyChanged 事件。

这是一个使用 Prism 的快速示例:

public sealed class UnicornViewModel : BindableBase

    public UnicornViewModel(string name, string content)
    
        Name = name;
        Content = content;
    

    // these properties don't change and therefore don't need to raise property changed
    public string Name  get; 

    public string Content  get; 


public sealed class UnicornsViewModel : BindableBase

    private UnicornViewModel _selectedUnicorn;

    public UnicornsViewModel()
    
        AddUnicornCommand = new DelegateCommand(AddUnicorn);
        ClearUnicornsCommand = new DelegateCommand(ClearUnicorns, () => HasUnicorns).ObservesProperty(() => HasUnicorns);
    

    public ObservableCollection<UnicornViewModel> Unicorns  get;  = new ObservableCollection<UnicornViewModel>();

    public UnicornViewModel SelectedUnicorn
    
        get => _selectedUnicorn;
        set => SetProperty(ref _selectedUnicorn, value, () => RaisePropertyChanged(nameof(HasUnicorns)));
    

    public DelegateCommand AddUnicornCommand  get; 
    public DelegateCommand ClearUnicornsCommand  get; 
    private bool HasUnicorns => Unicorns.Any(); // helper property for the clear command's can execute

    private void AddUnicorn()
    
        Unicorns.Add(new UnicornViewModel($"Unicorn Unicorns.Count + 1", Guid.NewGuid().ToString()));
        SelectedUnicorn = Unicorns.Last();
    

    private void ClearUnicorns()
    
        SelectedUnicorn = null;
        Unicorns.Clear();
    

【讨论】:

以上是关于使用 MVVM 将新项目添加到 TabControl ItemSsource 时选择最后一个 TabItem的主要内容,如果未能解决你的问题,请参考以下文章

在 WPF 中使用 MVVM 将 n 个矩形添加到画布

使用 MVVM 获取选定的 TreeViewItem

Xamarin 将字符串添加到 mvvm 中的条目

Xamarin.Forms 条目 - 自定义行为和 MVVM

WPF:如何使用 MVVM 将命令绑定到 ListBoxItem?

如何将 ListView 绑定到集合并实时刷新