How to update bindings when TabItem is selected? WPF - c#

I had the following code
<mah:MetroWindow x:Class="NeoTec.SprayMachine.WPF.MainWindow"
namespaces bla bla>
<Window.Resources>
<DataTemplate DataType="{x:Type viewModels:CompanyDatabaseViewViewModel}">
<controls:CompanyDatabaseViewControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:UserDatabaseViewViewModel}">
<controls:UserDatabaseViewControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:ParametersViewModel}">
<controls:ParamatersControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModels:SettingsViewModel}">
<controls:SettingsControl/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition/>
</Grid.RowDefinitions>
<controls:UpperPanelControl HorizontalAlignment="Center"/>
<ContentControl Grid.Row="1" Content="{Binding ShownViewModel}"/>
</Grid>
</mah:MetroWindow>
Where UpperPanelControl is a control with buttons that changes ShownViewModel in MainViewModel. For design purposes I decided to change this all to TabControl (there was a requirement from customer to have buttons):
<mah:MetroWindow x:Class="NeoTec.SprayMachine.WPF.MainWindow"
namespaces bla bla>
<TabControl>
<TabItem Header="Company Database">
<controls:CompanyDatabaseViewControl DataContext="{Binding CompanyDatabaseViewModel}"/>
</TabItem>
<TabItem Header="User Database">
<controls:UserDatabaseViewControl DataContext="{Binding UserDatabaseViewModel}"/>
</TabItem>
<TabItem Header="Parameters" IsSelected="{Binding ParametersTabSelected}">
<controls:ParamatersControl DataContext="{Binding ParametersViewModel}"/>
</TabItem>
<TabItem Header="Settings">
<controls:SettingsControl DataContext="{Binding SettingsViewModel}"/>
</TabItem>
<TabItem Header="Info">
<controls:InfoControl/>
</TabItem>
</TabControl>
</mah:MetroWindow>
It looks nicer, but the problem is when I switch tab the data in the tab is not updated. Are there any chance to get this working with TabControl with updating bindings, when tab is changed?

Each TabItem has an IsSelected property. You can bind that in your View Model and take the appropriate action.
<TabItem Header="Company Database" IsSelected="{Binding CompanyDataBaseTabIsSelected}">
<controls:CompanyDatabaseViewControl DataContext="{Binding CompanyDatabaseViewModel}"/>
</TabItem>
private bool _companyDatabaseTabIsSelected;
public bool CompanyDatabaseTabIsSelected
{
get { return _companyDatabaseTabIsSelected; }
set
{
_companyDatabaseTabIsSelected = value;
_companyDatabaseViewModel.Refresh();
}
}

Related

WPF Cannot position tabitem headers to left

I have a tab control in my WPF application and I'm trying to position the TabItem headers to the left as shown in this MSDN post using the below code (copied from the post):
<TabControl TabStripPlacement="Left" Margin="0, 0, 0, 10">
<TabItem Name="TabOne" Header="Tab One">
<TabItem.Content>
<TextBlock TextWrapping="WrapWithOverflow">
Tab One Here.
</TextBlock>
</TabItem.Content>
</TabItem>
<TabItem Name="TabTwo" Header="Tab Two">
<TabItem.Content>
<TextBlock TextWrapping="WrapWithOverflow">
Tab Two here.
</TextBlock>
</TabItem.Content>
</TabItem>
</TabControl>
According to the post this is what Im supposed to get:
But this is what I'm currently getting:
I've copied the exact same code from the post to my application and can't understand what has gone wrong.
Here is my full xaml:
<Window x:Class="OptionsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TabStripPlacementSample" Height="200" Width="250" UseLayoutRounding="True">
<Grid>
<TabControl TabStripPlacement="Left" Margin="0,0,33,10">
<TabItem Name="TabOne" Header="Tab One">
<TabItem.Content>
<TextBlock TextWrapping="WrapWithOverflow">
Tab One Here.
</TextBlock>
</TabItem.Content>
</TabItem>
<TabItem Name="TabTwo" Header="Tab Two">
<TabItem.Content>
<TextBlock TextWrapping="WrapWithOverflow">
Tab Two here.
</TextBlock>
</TabItem.Content>
</TabItem>
</TabControl>
</Grid>

How can one apply an itemtemplate to default TabItems?

I have the following TabControl with 2 default tabitems.
<TabControl>
<TabControl.ItemTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" Height="300" Content="{Binding}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabItem Header="Conexión"><local:ConnectionSettings/></TabItem>
<TabItem Header="Cuestionario"><local:QuestionEditor/></TabItem>
</TabControl>
The current xaml doesn't apply the ItemTemplate, for that to happen each tabitem would need to be "naked", like this:
<TabControl>
<TabControl.ItemTemplate>
<DataTemplate>
<ScrollViewer VerticalScrollBarVisibility="Auto" Height="300" Content="{Binding}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<!-- The ItemTemplate is only applied if tabitems are not wrapped in TabItem tags -->
<local:ConnectionSettings/>
<local:QuestionEditor/>
</TabControl>
But if I do that, then I can't specify the header.
I would like for every TabItem to be wrapped in a ScrollViewer (as specified in the ItemTemplate), but at the same be able to specify the header.
Is there a way to apply the ItemTemplate to <TabItem Header="MyHeader"/> tags?
ItemTemplate is the template to format the ItemsSource the headers on top of your tab control. ContentTemplate is the template to format the content of the tabs. To wrap your defined content to the scroll viewer, just make use of a new content control inside your template. Here is a minimal sample:
<TabControl>
<TabControl.ContentTemplate>
<DataTemplate>
<ScrollViewer>
<ContentControl Content="{TemplateBinding Property=ContentControl.Content}"/>
</ScrollViewer>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem>
<Button Content="Button1"/>
</TabItem>
<TabItem>
<Button Content="Button2"/>
</TabItem>
</TabControl>

How can I reuse same "Content Controller" in different tab (child) in XAML?

I have a TabControl in a XAML file like this:
<UserControl d:DesignHeight="300" d:DesignWidth="400">
<TabControl Style="{DynamicResource WizardTabControlStyle}">
<TabItem >
<local:Tab1/>
</TabItem>
<TabItem >
<local:Tab2/>
</TabItem>
<TabItem >
<local:Tab3/>
</TabItem>
</TabControl>
and every tab is defined in another xaml file:
<UserControl d:DesignHeight="450" d:DesignWidth="794">
<DockPanel DataContext="{Binding Model1}">
<GroupBox Header="{concept:Intl Key=Geometry, DefaultText='G1'}" DockPanel.Dock="Top" MinHeight="165">
<Grid>
// Common view
</Grid>
</GroupBox>
<GroupBox DockPanel.Dock="Bottom" Header="{concept:Intl Key=G2, DefaultText='G2'}" DataContext="{Binding G2}" Padding="0,10">
<Grid>
// other stuff
</Grid>
</GroupBox>
</DockPanel>
Other tab views are the same as this.
What I want to do is that define a graphical view (OpenGL) in the TabControl and then in the single tab XAML, I want a reference to that view. Every tab sin the "//Common view" should have the same OpenGL view defined in the Tab Control.
Is that possible?

How to bind elements in separate xaml files?

I have a MainWindow.xmal which has two TabItems:
<TabItem Header="Config" ... />
<TabItem Header="Results" ... />
I have a separated Config.xaml file for the Config TabItem which has a ListBox:
<ListBox Name="UrlConfig" ... />
I have another separated Results.xaml file for the Results TabItem which has a TaxtBlock:
<TextBlock Name="Url" .../>
The problem is that I'd like to bind the selected value in the ListBox to the TextBlock. How can I do that? Please help :)
I recomend you to work with MVVM, but if not you can implement it with XAML only:
Use sepparate resource like "Bridge" 'Config' and 'Results'
Config.xaml:
<UserControl x:Key="Config">
<ListBox x:Name="ListBox1" SelectedItem="{Binding Source={StaticResource SelectedValue}, Path=Y, Mode=TwoWay}" >
<System:String>Minsk</System:String>
<System:String>London</System:String>
<System:String>NY</System:String>
</ListBox>
</UserControl>
Results.xaml
<UserControl x:Key="Results">
<Label Name="Url" Content="{Binding Source={StaticResource SelectedValue}, Path=Y}" />
</UserControl>
Code of window with TabControl:
<Window.Resources>
<!--"Bridge" resource, here will be your own type-->
<X x:Key="SelectedValue" Y="Minsk"></X>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Config" Content="{StaticResource ResourceKey=Config}"/>
<TabItem Header="Results" Content="{StaticResource ResourceKey=Results}"/>
</TabControl>
</Grid>
If you're working in mvvm way you can bind those to a property on your viewmodel and set the DataContext for to that viewmodel

Show Open TabItem Names in a List View

I'm trying to display a list of open tab names in a listview or listbox (recommendations?).
Been going through the different type of binding options and I'm able to bind to a single tab name but it displays vertical instead of horizontal. Here is my XAML:
<ListView DockPanel.Dock="Left"
Height="352"
Name="listView1"
Width="132"
ItemsSource="{Binding ElementName=RulesTab, Path=Name}"
IsSynchronizedWithCurrentItem="True"
FlowDirection="LeftToRight"
HorizontalAlignment="Left"
HorizontalContentAlignment="Left"
DataContext="{Binding}">
Any pointers would be greatly appreciated as I'd like to be able to see a list of all the tabs open and then double click on one to bring the tab into focus. Many thanks!
Here is an example of a TabControl and a ListBox showing the names of the TabItems that are in it:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabControl Grid.Column="0" Name="tabControl1">
<TabItem Header="Tab1"/>
<TabItem Header="Tab2"/>
<TabItem Header="Tab3"/>
<TabItem Header="Tab4"/>
</TabControl>
<ListBox Grid.Column="1" ItemsSource="{Binding Items, ElementName=tabControl1}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_DoubleClick"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
and here's the code behind:
private void ListBoxItem_DoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
var tabItem = (TabItem)((ListBoxItem)sender).Content;
tabControl1.SelectedItem = tabItem;
}
Edited to add double-click behavior.
Simplified example how to enumerate the tabs in a tab control with a listview:
<TabControl Name="MyTabControl">
<TabItem Header="Tab1">
</TabItem>
<TabItem Header="Tab2">
</TabItem>
</TabControl>
<ListView DockPanel.Dock="Left"
ItemsSource="{Binding ElementName=MyTabControl, Path=Items}"
DataContext="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"></TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I'm still unsure as to what exactly you want, anyway, this can be adjusted if needed.
First of all if you bind to a specific item you will always have one item, you need to set ItemsSource to a collection.
Assuming you want to have the names or headers of all the tabs in your list you can set the tab control's Items as the ItemsSource and then apply a ItemTemplate, some example code:
<ListBox ItemsSource="{Binding ElementName=TabControlSrc, Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}" Margin="5"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
If you do not use the ItemTemplate you'll get an error because the same item can only be a visual child of one parent.
Frankly this seems a bit pointless since it just reiterates your tabs, did i misunderstand something? If so please clarify further.
Edit: Oh lol, three almost identical answers...

Categories