How do you access controls when using <TabItem.Header>, in code behind? - c#

Going off this sample from the MSDN under TabControl:
<TabControl>
<TabItem>
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Ellipse Width="10" Height="10" Fill="DarkGray"/>
<TextBlock>Tab 1</TextBlock>
</StackPanel>
</TabItem.Header>
<StackPanel>
<TextBlock>Enter some text</TextBlock>
<TextBox Name="textBox1" Width="50"/>
</StackPanel>
</TabItem>
<TabItem Header="Tab 2">
<!--Bind TextBlock.Text to the TextBox on the first
TabItem.-->
<TextBlock Text="{Binding ElementName=textBox1, Path=Text}"/>
</TabItem>
</TabControl>
How do you access the stackpanel (and it's children) that is inside the <TabItem.Header> tag from C# code behind? When I try to use .Header intellisense treats it as if the header was defined the way the 2nd tab above is.

I agree with HighCore. You should be using databinding instead of trying to manipulate the UI elements directly. In the off chance that you want to stick with your current plan, here's how:
<TabControl>
<TabItem>
<TabItem.Header>
<StackPanel Name="tab1StackPanel" Orientation="Horizontal">
...
</StackPanel>
</TabItem.Header>
</TabItem>
<TabItem Header="Tab 2">
...
</TabItem>
</TabControl>
Now, from code behind you can reference tab1StackPanel directly, as defining a Name exposes it to codebehind WPF (as long as it's not inside a template).
You could also use the VisualTreeHelper to find visual children of the first tab...
BUT... once again, you should probably be using databinding, so I'd make sure you're following a good pattern before going too much further.

I don't know if it works but you can give it a try:
(tabItem.Header as ContentControl).FindName("NAME_OF_TEXTBLOCK");

Related

WPF - How to properly Binding Header Items Count property of another component + custom text

I want to put a counter and a description on a TabItem Header:
<TabItem Header="{Binding ElementName=lista_etapas, Path=Items.Count,StringFormat=Etapas: {0}}">
But the StringFormat doesn't work. It only shows the Item Count property of the Datagrid 'lista_etapas'.
Expected: 'Etapas: 32'
Result:
Obs.: I Want to avoid using the <TabItem.Header>, because this creates some problems with my customs templates.
This code is working :
<ListBox Name="lista_etapas">
<ListBoxItem>A</ListBoxItem>
<ListBoxItem>B</ListBoxItem>
</ListBox>
<TabControl>
<TabItem Header="{Binding ElementName=lista_etapas,Path=Items.Count}"
HeaderStringFormat="Etapas: {0}">
</TabItem>
</TabControl>
<TabItem Header="{Binding ElementName=lista_etapas, Path=Items.Count,StringFormat={}Etapas: {0}}">
You need open, close brackets for StringFormat.
I've discovered that the "StringFormat" Property only works with binding Controls Property using a TextBlock/Label in header.
<TabItem.Header>
<TextBlock Text="{Binding ElementName=lista_emendas, Path=Items.Count,StringFormat={}Total: {0}}" />
</TabItem.Header>

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>

Changing Dragablz header color?

What I'm trying to achieve here is to change the white of the header text. (Dialogs, Mahapps, Palette) to something else and also the green below Dialogs. I tried changing the white to black using foreground property but that didn't do anything.
<dragablz:TabablzControl FixedHeaderCount="3" >
<TabItem Foreground="Black" Header="DIALOGS">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Hello World</TextBlock>
</TabItem>
<TabItem Header="MATERIAL">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Material Design</TextBlock>
</TabItem>
<TabItem Header="PALETTE">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Looks Quite Nice</TextBlock>
</TabItem>
</dragablz:TabablzControl>
You can add your "own" TextBlock element to the Header of the TabItem, and there set the Foreground brush (and override any styles that might otherwise affect it) like this:
<TabItem>
<TabItem.Header>
<TextBlock Text="DIALOGS" Foreground="Black" />
</TabItem.Header>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">Hello World</TextBlock>
</TabItem>

Why doesn't my styled ToggleButton work on the second tab of a TabControl?

I encountered a problem when I was developing a WPF application with a TabControl object. I tried to debug and find the problem and finally I've got it, but I didn't find any workaround to it. Here is some explanation:
I used this data grid filtering library (here is a codeproject url), which is the best (from my viewpoint). I want to customize it with the google material design theme and change some graphical features, such as using a toggle button in the first tab header of data gird to hide/show the filtering option.
I created a user control and placed my custom datagrid in it. Then I embedded that control into the tabItem. When I set this control to the first tabItem, everything works correctly. But when I change the user control to the other tabItem, the toggle button does not work.
Here is my main window xaml code that didn't work:
<TabControl x:Name="tabControl">
<TabItem Header="1'st Tab">
<ContentControl DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Button Content="Do no thing"></Button>
</ContentControl>
</TabItem>
<TabItem Header="2'nd Tab">
<ContentControl DataContext="{Binding Path=DataContext, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<local:UserControl1/>
</ContentControl>
</TabItem>
</TabControl>
Note that if I change the order of TabItems, it works well. Does anyone have a suggestion how to solve this problem? Here is my sample project code on Github
Edit: Today, I test my application with "WPF Inspector" to find the structure of visual and logical tree. The behavior was too strange because when I attached "WPF Inspector" to my application, everything started to work. The below GIF is what I did:
When using a ContentControl for a Data-Object, in your case it's the data context, you bind the Content property to the Data-Object and specify the DataTemplate property. In this case the content within DataTemplate will have its DataContext set to your Data-Object.
Here is a working sample:
<TabControl x:Name="tabControl">
<TabItem Header="1'st Tab">
<ContentControl Content="{Binding .}">
<ContentControl.ContentTemplate>
<DataTemplate>
<Button Content="Do no thing"></Button>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</TabItem>
<TabItem Header="2'nd Tab">
<ContentControl Content="{Binding .}">
<ContentControl.ContentTemplate>
<DataTemplate>
<local:UserControl1/>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</TabItem>
</TabControl>

WPF .NET4.0 re-use same instance of UserControl

I'd like to display the same instance of user control twice. Ive tried doing the following:
<UserControl.Resources>
<Views:MyControl View x:Key="_uc1" MinHeight="300"/>
</UserControl.Resources>
And trying to use it in a TabControl:
<TabControl Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="3" >
<TabItem >
<TabItem.Header>
<TextBlock Text="Header1" FontWeight="13"/>
</TabItem.Header>
<StackPanel >
<ContentControl Content="{StaticResource _uc1}"/>
</StackPanel>
</TabItem>
<TabItem >
<TabItem.Header>
<TextBlock Text="Header2" FontWeight="13"/>
</TabItem.Header>
<StackPanel MinHeight="600" >
<ContentControl Content="{StaticResource _uc1}"/>
</StackPanel>
</TabItem>
</TabControl>
Im getting the error message:
"{"Specified element is already the logical child of another element. Disconnect it first."}"
Is what Im trying to achieve possible?
Thanks,
It's not. As the error indicates, a given object may only be present in a given logical tree once. This helps to ensure that the logical tree remains a tree.
If you're using the MVVM pattern (or are just using DataBinding in general,) then you can bind two different UserControls to the same backing ViewModel/data, so that the controls will behave the same and operate on the same state representation. You'll still need two different controls, though.
In WPF (and Silverlight) a control cannot be in more than one place in the visual tree. What you can do is have two separate instances of the user control, but bind their relevant properties to the same underlying source.
For example, let's say you had a Contact object and you wanted two MyControl instances to refer to the same FullName property.
<UserControl>
<UserControl.Resources>
<my:Contact x:Key="data" FullName="Josh Einstein" />
</UserControl.Resources>
<TabControl DataContext="{StaticResource data}">
<TabItem>
<TabItem.Header>
<TextBlock Text="Header1" FontWeight="13" />
</TabItem.Header>
<StackPanel>
<!-- instance #1 -->
<Views:MyControl FullName="{Binding FullName, Mode=TwoWay}" />
</StackPanel>
</TabItem>
<TabItem>
<TabItem.Header>
<TextBlock Text="Header2" FontWeight="13" />
</TabItem.Header>
<StackPanel>
<!-- instance #2 -->
<Views:MyControl FullName="{Binding FullName, Mode=TwoWay}" />
</StackPanel>
</TabItem>
</TabControl>
</UserControl>
If you just want a single control to appear in multiple places in the visual tree, but not actually be interactive, you can use a VisualBrush to "paint" onto another control.
You can not have the same control in two places, but you make it jump, see this answer of mine for an example of how to do that.

Categories