WPF 动态选项卡控件选择更改了错误

本文关键字:错误 选择 控件 动态 选项 WPF | 更新日期: 2023-09-27 18:34:28

我正在使用 MVVM 模式使用 C# 和 WPF 创建一个简单的应用程序。有一个带有几个按钮的主窗口和一个包含视图模型列表的 ContentControl,其中一个是 SearchViewModel。按钮在视图模型之间翻转。

SearchViewModel 绑定到 SearchView 并包含一个 TabControl。属性绑定到 SearchTabViewModel 的列表。在 SearchViewModel 的构造函数中,我正在初始化 SearchTabViewModel 的 ObservableCollection,然后添加两个选项卡。第一个选项卡的标题为"+",另一个选项卡是普通搜索选项卡。TabControl 的 SelectionChanged 事件绑定到检查是否单击了"+"选项卡的方法。如果是,则在"+"选项卡之前插入一个新选项卡,并且 TabControl 的 SelectedIndex 属性设置为插入的选项卡的索引。相当简单的设置。

我遇到的问题是,当应用程序首次运行时,您可以单击"+"选项卡并插入一个新选项卡,但随后"+"选项卡已失效,单击它时没有任何反应。事件不会触发。我已经检查过并且 SelectedIndex 设置为它前面的选项卡,因此它不是选定的选项卡。要修复它,您必须先单击另一个选项卡,然后一切正常。它只是在开始时冻结一次。

任何人都可以看到问题可能是什么吗?我包括代码的相关部分:

XAML

<TabControl 
    Name="searchTabControl" ItemsSource="{Binding Path=SearchTabs}"
    SelectedIndex="{Binding Path=SelectedTabIndex}"
    ItemTemplateSelector="{Binding Source={StaticResource searchTabTemplateSelector}}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged" >
            <i:InvokeCommandAction 
                CommandName="searchTabHasChanged" Command="{Binding SelectionChangedCommand}"
                CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=CommandName}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    ....more code

搜索视图模型

public class SearchViewModel : ObservableObject, IPageViewModel
{
    #region Fields
    public ObservableCollection<SearchTabViewModel> SearchTabs { get; set; }
    private int _selectedTabIndex;
    private ICommand _selectionChangedCommand;
    #endregion
    public SearchViewModel()
    {
        try
        {
            // initialize the SearchTabs array
            this.SearchTabs = new ObservableCollection<SearchTabViewModel>();
            // add a tabItem with + in header 
            SearchTabViewModel tabAdd = new SearchTabViewModel("+");
            this.SearchTabs.Add(tabAdd);
            // add first tab
            AddTabItem();
            SelectedTabIndex = 0;
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
    #region Properties/Commands
    public int SelectedTabIndex
    {
        get { return _selectedTabIndex; }
        set
        {
            _selectedTabIndex = value;
            OnPropertyChanged("SelectedTabIndex");
        }
    }
    public ICommand SelectionChangedCommand
    {
        get
        {
            if (_selectionChangedCommand == null)
            {
                _selectionChangedCommand = new RelayCommand(
                    param => TabSelectionChanged(param)
                );
            }
            return _selectionChangedCommand;
        }
    }
    #endregion
    #region Methods
    public void TabSelectionChanged(Object source)
    {
        if (source.ToString() == "searchTabHasChanged")
        {
            SearchTabViewModel tab = this.SearchTabs[SelectedTabIndex];
            if (tab != null && tab.Header != null)
            {
                if (tab.Header.Equals("+"))
                {
                    // add new tab
                    SearchTabViewModel addedTab = AddTabItem();
                    // select newly added tab item
                    SelectedTabIndex = this.SearchTabs.IndexOf(addedTab);
                }
            }
        }
    }
    private SearchTabViewModel AddTabItem()
    {
        int count = SearchTabs.Count;
        // create new tab item
        SearchTabViewModel tab = new SearchTabViewModel();
        tab.Header = string.Format("Tab {0}", count);
        // insert tab item right before the last (+) tab item
        this.SearchTabs.Insert(count - 1, tab);
        return tab;
    }
    #endregion
}

另外,我注意到的另一个奇怪的行为是,当您第一次运行应用程序并单击"+"选项卡一次以添加新选项卡并且"+"选项卡死亡时,如果应用程序失去焦点并再次获得焦点,SelectionChanged 事件将触发并添加新选项卡?仅当"+"选项卡失效时,才会发生此行为。通过单击另一个选项卡修复它后,此行为将消失。

WPF 动态选项卡控件选择更改了错误

在 TabSelectionChanged 中,您可以添加一个新的 TabItem 并紧接着更改 SelectedTabIndex。问题是在视图中生成新 TabItem 的 ItemContainerGenerator 尚未触发。这是在数据绑定阶段完成的。因此,当您设置SelectedTabIndex时,您实际上将其设置为(已选择(+选项卡。

若要解决此问题,请通过调用优先级低于 DataBinding 的调度程序上的调用来推迟 SelectedTabIndex 的更改。

this.Dispatcher.BeginInvoke(() => SelectedTabIndex = this.SearchTabs.IndexOf(addedTab), DispatcherPriority.Background);