How to change TabControl selected tab - c#

I have a TabControl on a window which has three tabs in total. I would like to select the first tab programmatically. I've tried TabControlMain.SelectedItem = 0, but this doesn't work. How can I do this?
<TabControl x:Name="TabControlMain">
<TabItem x:Name="TabItemA" Header="A">
...
</TabItem>
<TabItem x:Name="TabItemB" Header="B">
...
</TabItem>
<TabItem x:Name="TabItemC" Header="C">
...
</TabItem>
</TabControl>

You can set TabControl.SelectedIndex = 0 (docs)
Or set YourDesiredTabItem.IsSelected = true (docs)
TabControl.SelectedItem can only be a TabItem object or null (docs).

Related

Cannot hook up the view because of the Data Context (WPF)

So my problem is that, initially I got the following code in my MainWindow.xaml class
<Button Margin="10,20,10,10" Height="37" Command="{Binding AddCmd}">View all customers</Button>
....
<TabControl x:Name="myTabs" ItemsSource="{Binding WorkSpaces}" Height="323">
<TabControl.Resources>
<DataTemplate DataType="{x:Type viewmodel:AllCustomersViewModel}">
<views:AllCustomersView/>
</DataTemplate>
</TabControl.Resources>
<TabControl.ItemTemplate>
....
</TabControl.ItemTemplate>
</TabControl>
and in the MainWindow.xaml.cs class, I have this code
public MainWindow()
{
InitializeComponent();
this.DataContext = new DemoWPFApp.ViewModel.MainWindowViewModel();
myTabs.DataContext = this.DataContext; //that is where the problem is
}
So, basically what I want is that when I click the button "View All Customers" it will add a new AllCustomerViewModel to the list of WorkSpaces, and show the AllCustomerView on the screen.
However, I cannot do this. BUT when I delete the line "myTabs.DataContext = this.DataContext;" in the MainWindow.xaml.cs class, it works !
Can someone explain to me why ? Because I already set my AllCustomerView data context to be AllCustomerViewModel. And I cannot understand why that line is the problem of my application.
Thank you.

Explore a WPF TabItem

I want to get the content of a graphical elements present in a WPF TabItem.
Consider the following code for the window :
<TabItem x:Name="TheItem" Header="Form">
<Grid x:Name="MainGrid">
<TextBox x:Name="txtContent" Text="Hello I'm some content !" />
<TextBox x:Name="txtOther" Text="Some other content" />
</Grid>
</TabItem>
I've looked up the TabItem documentation on MSDN but failed to find any useful information.
Is there any way to get the content from the "txtContent" textbox from a TabItem ?
Try this:
Grid grid = TheItem.Content as Grid;
TextBox txtContent = grid.Children[0] as TextBox;
string text = txtContent.Text;
Or simply:
TextBox txtContent = MainGrid.Children[0] as TextBox;

WPF changing several properties one after another

I have a TabControl that contains a TextBox per tab. I need to select a tab programmatically and then set the selection of the TextBox and set the focus to the TextBox.
My problem is, when I first select a new tab in code and then set the focus to the textbox it doesn't work.
When the desired tab is already the selected tab and I set the focus to the textbox inside the tab, it's working.
It seems, that performing several actions on WPF elements does not work.
What is the right way to first switch the tab of a tabcontrol and then set the focus to a child in the newly selected TabItem?
Edit: I've found something on the Internet: Waiting for the render thread to complete:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/693fbedb-efa6-413e-ab66-530c6961d3fb/how-to-wait-for-the-wpf-render-thread-to-catch-up?forum=wpf
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => { })).Wait();
But is this the right way?
BTW: What is the difference between:
Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => { })).Wait();
Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => { }));
Use the FocusManager.SetFocusedElement() method.
Focus has some nuances, you can learn more here.
XAML
<TabControl>
<TabItem Header="One"
x:Name="tabOne">
<Button HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="Set Focus"
Click="Button_Click" />
</TabItem>
<TabItem Header="Two"
Name="tabTwo">
<StackPanel>
<TextBox Name="txtOne" />
<TextBox Name="txtTwo" />
</StackPanel>
</TabItem>
<TabItem Header="Three"
x:Name="tabThree">
<StackPanel>
<TextBox Name="txtThree" />
<TextBox Name="txtFour" />
</StackPanel>
</TabItem>
</TabControl>
CODE
private void Button_Click(object sender, RoutedEventArgs e)
{
tabTwo.IsSelected = true;
FocusManager.SetFocusedElement(tabTwo, txtTwo);
}

Keyboard shortcuts not working until I click a control in the View for MVVM

I'm having a weird problem. I binded some keyboard shortcuts like so:
BroadcastView XAML:
<UserControl.InputBindings>
<KeyBinding Key="F1" Command="{Binding StartRoundClockCmd}"/>
<KeyBinding Key="F2" Command="{Binding StopRoundClockCmd}"/>
</UserControl.InputBindings>
MainWindow XAML
<Grid>
<TabControl>
<TabItem Header="Broadcast">
<view:BroadcastView/>
</TabItem>
<TabItem Header="Options">
<view:OptionsView/>
</TabItem>
</TabControl>
</Grid>
but the problem is.. when I start the application.. F1 and F2 don't work.. i can click anywhere within the TabItem thinking I just need it to focus the tabitem.. but still nothing.. it's only when I click within a textbox.. or click a button on the View (within the TabItem) first.. THEN the keyboard shortcuts work.
how can I get it so that the keyboard shortcuts will work from application startup using MVVM?
I would use Keyboard.Focus and FocusManager if I were you.
You can set the focus on your usercontrol so it receives the keyboard shortcuts.

How to right-align last TabControl tab?

Is there a way to make last tab on TabControl right-aligned ?
Want to make the last one separate from the first few.
Thanks !
This post may be old, but i stumbled across it while searching for an answer to the same question, so i thought I'd share the quick and dirty solution I ended up with.
I just put two TabControls on top of each other in a Grid, and right-aligned the TabPanel on one of them (thanks go out to Meleak):
<Grid>
<TabControl x:Name="_tabsRight" GotFocus="OnTabFocused" >
<TabControl.Resources>
<Style TargetType="TabPanel">
<Setter Property="HorizontalAlignment" Value="Right"/>
</Style>
</TabControl.Resources>
<TabItem x:Name="JustAHiddenTabItemToDeselectTheRealOne" Visibility="Hidden" />
<!-- Last tab -->
<TabItem Header="Last one" >
<!-- Last content... -->
</TabItem>
</TabControl>
<TabControl x:Name="_tabsLeft" GotFocus="OnTabFocused" >
<!-- First tab -->
<TabItem Header="1st" >
<!-- First content... -->
</TabItem>
<!-- Second tab -->
<TabItem Header="2nd" >
<!-- Second content... -->
</TabItem>
</TabControl>
</Grid>
Then, in the OnTabFocused event handler, we need to bring the bottom-most TabControl to the front when the user clicks a TabItem:
private int _zIncrementor = 0;
/// <summary>
/// Hack to make two TabControls act as one.
/// </summary>
private void OnTabFocused(object sender, RoutedEventArgs e)
{
var tab = (TabControl)sender;
var otherTab = (tab == _tabsLeft) ? _tabsRight : _tabsLeft;
Grid.SetZIndex(tab, ++_zIncrementor);
otherTab.SelectedItem = null;
}
Here is an example project on templating the TabControl tabs. I would probably use a Grid with three columns of width "Auto", * and "Auto" and put a StackPanel in the first column to hold the first set of tabs and then just the last tab by itself in the last column with the middle column being empty and just taking up the remaining space.
If you want to have two tabs at left and one at right, You can have the third invisible tab inbetween and width of the invisible tab can be calculated by subtracting the Width of all three visible tabs from the Actualwidth of the Window which gives us the remaining space.
Here is the sample code
<TabControl x:Name="_tabsLeft" GotFocus="OnTabFocused" >
<!-- First tab -->
<TabItem Header="1st" >
<!-- First content... -->
</TabItem>
<!-- Second tab -->
<TabItem Header="2nd" >
<!-- Second content... -->
</TabItem>
<!-- Third invisible tab -->
<TabItem Header="Im not visible in UI" Visibility="Hidden" x:Name="invisibletab" >
<!-- I'm not visible in UI... -->
</TabItem>
<!-- Last tab -->
<TabItem Header="Last one" >
<!-- Last content... -->
</TabItem>
</TabControl>
Backend Code:
public MainWindow()
{
InitializeComponent();
this.SizeChanged += window_SizeChanged;
}
private void window_SizeChanged(object sender, SizeChangedEventArgs e)
{
invisibletab.Width = this.ActualWidth - 550; // where the 550 is the sum of the actual width of visible tabs
}

Categories