WPF动态TabControl SelectionChanged错误?

时间:2014-12-16 06:04:25

标签: c# wpf dynamic mvvm tabcontrol

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

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

我遇到的问题是,首次运行应用程序时,您可以点击" +"选项卡并插入一个新选项卡,然后选择" +"选项卡已经死了,单击它时没有任何反应。 SelectionChanged事件不会触发。我已经检查过,并且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

SearchViewModel

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
}

此外,我注意到的另一个奇怪的行为是,当您第一次运行应用程序并单击&#34; +&#34;标签一次添加新标签和&#34; +&#34;选项卡死亡,如果应用程序失去焦点并再次获得焦点,则会触发SelectionChanged事件并添加新选项卡?这种行为只发生在&#34; +&#34;标签已经死了。通过单击另一个选项卡修复它后,此行为将消失。

1 个答案:

答案 0 :(得分:1)

在TabSelectionChanged中,添加一个新的TabItem并相互更改SelectedTabIndex。问题是尚未触发在视图中生成新TabItem的ItemContainerGenerator。这是在DataBinding阶段完成的。因此,当您设置SelectedTabIndex时,实际上将其设置为(已选中)+选项卡。

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

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