tags:

views:

58

answers:

2

I have a problem with the selected item in WPF-TabControl that could be reproduced with the following simplified code:

If a new TabItem is created and selected through the Click-event of the button in the second window, the tab is created, added and selected. When the second window will be closed, the selected item of the tab-control is reset to the last selected item. The problem occurs in my MVVM-app and it is independent of the Items-collection. I can use the ItemsSource or the Items-Collection, it happens always.

Has someone an idea what happens here or has a nice workaround?

TabControl tabControl = new TabControl() ;
tabControl.Items.Add(new TabItem { Header="InitialTabItem"});
((TabItem)tabControl.Items[0]).Focus();
Window mainWindow = new Window() { Content=tabControl,Title="TabControl-Window"};
mainWindow.Show();            
Button addButton = new Button() { Content="AddTabItem"};
addButton.Click += (o, e) => {
        TabItem newTabItem=new TabItem(){Header=DateTime.Now.ToLongTimeString()};
        tabControl.Items.Add(newTabItem);                
        tabControl.SelectedItem = newTabItem;                
};
Window directorWindow = new Window() { Owner = mainWindow ,Content=addButton,Height=80,Width=200,Title="DirectorWindow"};
directorWindow.Show();

Update

It seems to be as always when I have bigger problems with WPF, to be an issue with focus-management. If I change the creation-code as follows, it works:

TabItem newTabItem=new TabItem(){Header=DateTime.Now.ToLongTimeString()};
tabControl.Items.Add(newTabItem);                    
Dispatcher.BeginInvoke(new Action(delegate{
    newTabItem.Focus();
    tabControl.SelectedItem = newTabItem;
}), System.Windows.Threading.DispatcherPriority.Input, null);

However it looks not very confidently to me. Some ideas?

+1  A: 

Yeah, TabControl behaves strange sometimes. In our project we had to create a subclass and override some methods to workaround another bug in it.

In your case, everything seems to work if you focus the TabControl itself before focusing the TabItem:

        var tabControl = new TabControl();
        var tabItem = new TabItem { Header = "InitialTabItem" };
        tabControl.Items.Add(tabItem);
        tabControl.Focus();
        tabItem.Focus();
        Window mainWindow = new Window() { Content = tabControl, Title = "TabControl-Window" };
        mainWindow.Show();
        Button addButton = new Button() { Content = "AddTabItem" };
        addButton.Click += (o, args) =>
        {
            TabItem newTabItem = new TabItem() { Header = DateTime.Now.ToLongTimeString() };
            tabControl.Items.Add(newTabItem);
            tabControl.SelectedItem = newTabItem;
        };
        Window directorWindow = new Window() { Owner = mainWindow, Content = addButton, Height = 80, Width = 200, Title = "DirectorWindow" };
        directorWindow.Show();

Update 1. See comments -- the original code causes bad side effects.

        var tabControl = new TabControl();
        var tabItem = new TabItem { Header = "InitialTabItem" };
        tabControl.Items.Add(tabItem);
        Window mainWindow = new Window() { Content = tabControl, Title = "TabControl-Window" };
        mainWindow.Show();
        tabControl.Focus();
        tabItem.Focus();
        Button addButton = new Button() { Content = "AddTabItem" };
        addButton.Click += (o, args) =>
        {
            TabItem newTabItem = new TabItem() { Header = DateTime.Now.ToLongTimeString() };
            tabControl.Items.Add(newTabItem);
            tabControl.SelectedItem = newTabItem;
        };
        Window directorWindow = new Window() { Owner = mainWindow, Content = addButton, Height = 80, Width = 200, Title = "DirectorWindow" };
        directorWindow.Show();
Yacoder
+1 You're right, in my demo-project this helps indeed. I will try later in the real application (I must finish something else before). Do you know why it behaves like this?
HCL
I guess, because no one in Microsoft verified this scenario and the logic of Focus() itself so complicated, so no human can verify its correctness for all possible cases through code review?
Yacoder
@Yacoder: Bad news. I testet the workaround in the real app - It solved the main problem, however after closing the window, the focus-management goes crazy. One of the result is that TreeViewItems are no more selectable. It seems that I have found here a major issue. Thanks however for your answer. Was a good solution. I will look for another workaround.
HCL
@Yacooder: I posted myself an answer, because with this solution, I had other issues (even bigger) and I think this will also happen to other users which have an analog issue. However your answer resolved the question I have initialy asked. Therefore the acceppt should be yours. Tell me, if I should accept your answer or the mine (or maybe in the meantime another post will show the real solution). Thanks for your answer and your time.
HCL
I'm almost sure you can solve it by focusing controls in the right order. Maybe it should go like Window -> TabControl -> TabPage.
Yacoder
Also, it might help to only call the Focus() methods after we create the main window and show it.
Yacoder
@Yacoder: Tried also Window -> TabControl -> TabPage. Its always the same effect. It seems that it is not a good idea to engage Win32-functionality (I assume focus mgmt under multiple windows is done via Win32) from within an unfinished event. The only solution that seems to work is really to make the selection after the event has been finished and all internal operation-state has been reset (through Dispatcher).
HCL
A: 

See Yacoders solution that solves the issue with the demo-code. However led this solution to focus-issues in my real project.

A way that seems to work for me is the way I showed in my update. If someone has the same problem, try the following code. Up to now, I have not seen any side-effects.

TabControl tabControl = new TabControl() ;  
tabControl.Items.Add(new TabItem { Header="InitialTabItem"});  
((TabItem)tabControl.Items[0]).Focus();  
Window mainWindow = new Window() { Content=tabControl,Title="TabControl-Window"};  
mainWindow.Show();              
Button addButton = new Button() { Content="AddTabItem"};  
addButton.Click += (o, e) => {  
    TabItem newTabItem=new TabItem(){Header=DateTime.Now.ToLongTimeString()};   
    tabControl.Items.Add(newTabItem);                       
    Dispatcher.BeginInvoke(new Action(delegate{   
       newTabItem.Focus();   
       tabControl.SelectedItem = newTabItem;   
    }), System.Windows.Threading.DispatcherPriority.Input, null); 
};  
Window directorWindow = new Window() { Owner = mainWindow ,Content=addButton,Height=80,Width=200,Title="DirectorWindow"};  
directorWindow.Show();  
HCL