3

I have a WPF window with a maintabWindow and several tabitems. It normally works fine and the layout is this:

enter image description here

but when I BEFORE add the following window:

enter image description here

the result is this:

enter image description here

So the problem is related with the tabControl/tabItem refresh. This is fairly obvious but even more because if I move the window or pass with the mouse on the a tabItem they get refreshed one by one.

I searched and found that here is a solution: http://geekswithblogs.net/NewThingsILearned/archive/2008/08/25/refresh--update-wpf-controls.aspx

so I added:

  this.MainTab.Refresh();
  this.tabItem1.Refresh();
  this.tabItem2.Refresh();
  this.tabItem3.Refresh();
  this.tabItem4.Refresh();
  this.tabItem5.Refresh();

but that didn't change a thing.

Thanx for any help

Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
Patrick
  • 3,073
  • 2
  • 22
  • 60
  • 1
    Can you, please, post some XAML? – Spawn Nov 28 '15 at 21:13
  • You could try something like this: http://xcalibursystems.com/tag/tab-control/ – Xcalibur37 Nov 29 '15 at 13:51
  • @Xcalibur37 alas not working. BUT the other solution that you proposed as potentially not working.... works. So In any case thanx for your help!!!! You might propose it as a solution if you want. – Patrick Nov 29 '15 at 18:28
  • Been blocked while editing comment. This one works fine.... for (var i = 0; i < myTabControl.Items.Count; i++) { myTabControl.SelectedIndex = i; myTabControl.UpdateLayout(); } – Patrick Nov 29 '15 at 18:35
  • I had a similiar problem. `mainTab.Update()` did the trick for me. – programmerRaj Mar 08 '20 at 00:08

2 Answers2

2

Ok so in the end it has a quite a weird behavious. If I do

for (int i = 0; i < tbcMain.Items.Count; i++)
  {
    tbcMain.SelectedIndex = i;
    tbcMain.UpdateLayout();
  }

it works. But I have to set the 1st tabitem so if I add

 tbcMain.SelectedIndex = 0;

it doesn't. So the solution was put a sleep and it works again.

for (int i = 0; i < tbcMain.Items.Count; i++)
  {
    tbcMain.SelectedIndex = i;
    tbcMain.UpdateLayout();
  }

  System.Threading.Thread.Sleep(250);
  tbcMain.SelectedIndex = 0;

But that is not elegant at all. If anyone has a better solution pls let me know it. Btw adding the tbcMain.SelectedIndex = 0; on the loaded event of the mainWindow is of no use.

Patrick
  • 3,073
  • 2
  • 22
  • 60
  • Don't add `tbcMain.SelectedIndex = i;` in your loop. It's not needed. You can just do `tabItem1.UpdateLayout()`, `tabItem2.UpdateLayout()`, etc. directly. If you want to do a loop, just append `i` to the TabItem name. Then you set your `.SelectedIndex = 0` at the end, like you did, or set it first. – vapcguy Jan 12 '17 at 16:44
0

You should be able to set your SelectedIndex first, and without having to include it in your loop:

tbcMain.SelectedIndex = 0;

Then, basing it off of your response, you should be able to either just do .UpdateLayout() on each of your TabItems:

MainTab.UpdateLayout();
tabItem1.UpdateLayout();
tabItem2.UpdateLayout();
tabItem3.UpdateLayout();
tabItem4.UpdateLayout();
tabItem5.UpdateLayout();

Or you should be able to do something like this in your loop:

MainTab.UpdateLayout();
for (int i = 0; i < tbcMain.Items.Count; i++)
{
    TabItem tbi = (TabItem)this.FindControl("tabItem"+i);
    tbi.UpdateLayout();
}

Updating/refreshing should have nothing to do with setting the selected one. Including the selection of the tab within the loop to i was your problem - not a race condition. Set the tbcMain.SelectedIndex = 0 outside of your loop and you should be fine. Sometimes, however, this doesn't work and you need to set it with Dispatcher:

Dispatcher.BeginInvoke((Action)(() => this.tbcMain.SelectedIndex = 0));

There's a write up/comments on a separate thread regarding why it needs to be sent to Dispatcher:

How to programmatically select a TabItem in WPF TabControl

Though, unfortunately for me, I had a similar issue where I was trying to refresh a ListView on a subtab. Neither .UpdateLayout(), nor .InvalidateVisual() (as I saw on this thread) worked. I just had to rebind my grid in the button event I was using on my main page, so that when the tab was clicked, it was refreshed manually. I added an x:Name property on the tab so I could call it using "dot" syntax, and it exposed the ListView. I simply added the DataTable of results back to that ListView's DataContext.

Community
  • 1
  • 1
vapcguy
  • 7,097
  • 1
  • 56
  • 52