How can I create an TextBox in WPF ( With XAML ) that there is an button inside it, Just like Google Chrome Adressbar.
I want somethings like the picture below :
And then how can I change the position of the button to the right and left ? ( I'm using C# )
You could nest the button inside a Grid on top of the TextBox, since it sounds like you only need to use this once:
e.g.
<Grid>
<TextBox Text="Hello" />
<Button HorizontalAlignment="Right" Content="Click Me" />
</Grid>
The only issue with this is that the text will show under the button. An alternative is to make your own usercontrol or to edit the controltemplate of the textbox (but this will probably not have the functionality you want).
I'd create a textbox in the left column of a 2 column grid, then the button in the right column. Then remove the background and border on the textbox and put this background/border on the grid. This will give the appearance of a textbox with a button in where the text can't go underneath the button
e.g.
<Border BorderBrush="LightGray" BorderThickness="1" Height="30">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox VerticalAlignment="Center" BorderBrush="Transparent" Background="Transparent" Text="Hello World this is a really long bit of text that wont go underneath the button (it will get clipped)"></TextBox>
<Button Content="Click me" Grid.Column="1" Margin="4"></Button>
</Grid>
</Border>
Only problem you have with that is that you don't get the chrome hover effect etc etc. Usercontrol with control template is your best option, but this gives you some ideas
The way to do this :
<Border x:Name="TextboxBorder" BorderBrush="#FFB8AAAA" BorderThickness="1" Grid.Column="2" Margin="3,1.5,4.084,1.5" Height="27" Background="White" CornerRadius="3">
<Grid x:Name="TextboxGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="33"/>
</Grid.ColumnDefinitions>
<Button x:Name="btn" Grid.Column="1" Margin="3.5,4.833,4.5,3.5" BorderBrush="{x:Null}" Style=" {DynamicResource SearchButtonStyle}" >
<Button.Background>
<ImageBrush ImageSource="Images/search.png"/>
</Button.Background>
</Button>
<TextBox Padding="0,1.2,0,0" x:Name="txt" Margin="1.541,0.5,2.041,0.5" TextWrapping="Wrap" Text="سلام" BorderThickness="0" FontSize="16"/>
</Grid>
</Border>
And the Button style is :
<Style x:Key="SearchButtonStyle" TargetType="{x:Type Button}">
<Setter Property="FocusVisualStyle" Value="{StaticResource ButtonFocusVisual}"/>
<Setter Property="Background" Value="{StaticResource ButtonNormalBackground}"/>
<Setter Property="BorderBrush" Value="{StaticResource ButtonNormalBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border BorderThickness="0" Margin="1.875,0.5,1.75,-0.375" Background="{TemplateBinding Background}" Width="16" Height="16"/>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocused" Value="true"/>
<Trigger Property="ToggleButton.IsChecked" Value="true"/>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#ADADAD"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And Then WPF Rocks!!!
Related
I am trying to achieve something that's driving me nuts, it partially works, but I can't achieve the same results that I did on my old Winforms project(I am trying to learn WPF and move away from Winforms).
I am trying to paint a Button if I place the mouse over it, so it change the background color and add a yellow rectangle on the left like this:
I tried to create with much difficulty a Styled button that partially do the job, it changes the background color but I can't figure out how to paint the yellow rectangle
<Style x:Key="MenuButton" TargetType="Button">
<Setter Property="Button.Background" Value="#525864"/>
<Setter Property="Button.Foreground" Value="#ffffff" />
<Setter Property="Button.BorderThickness" Value="0"/>
<Setter Property="Button.Margin" Value="10,0,0,0"/>
<Setter Property="Button.Height" Value="40"/>
<Setter Property="Button.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
**
<Setter Property="Rectangle.Fill" Value="#f0e68c"/> **
<Setter Property="Button.Background" Value="#737b8c"/>
</Trigger>
</Style.Triggers>
</Style>
From the main Window I created the button like this:
<Button Style="{StaticResource MenuButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Column="0" Width="10"/>
<TextBlock Grid.Column="1" Text="Comparador Archivos" Margin="5,0,0,0"
HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Image Grid.Column="2" Margin="5" Source="/Imagenes/icono_comparar.png"/>
</Grid>
</Button>
Because the Content in the ContentPresenter is set on the UI, the style does not know the existence of the Rectangle. Therefore, to access the Rectangle, you need to insert <Grid> ~ </Grid> directly instead of <ContentPresenter/>.
And in Style.Trigger, objects in the ControlTemplate is not accessible.
Therefore, it must be processed within ControlTemplate.Triggers.
By giving x:name to the Rectangle, internal properties can be accessed in Trigger.
<Style x:Key="MenuButton" TargetType="Button">
<Setter Property="Background" Value="#525864"/>
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Margin" Value="10,0,0,0"/>
<Setter Property="Height" Value="40"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Rectangle x:Name="rec" Grid.Column="0" Width="10"/>
<TextBlock Grid.Column="1" Text="Comparador Archivos" Margin="5,0,0,0"
HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Image Grid.Column="2" Margin="5" Source="/Imagenes/icono_comparar.png"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="rec" Property="Fill" Value="#f0e68c"/>
<Setter Property="Background" Value="#737b8c"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Button Style="{StaticResource MenuButton}"/>
Cant you just change the fill hex so one of these
<Setter TargetName="rec" Property="Fill" Value="#f0e68c"/> <Setter Property="Background" Value="#737b8c"/>
Change the hex of Value="#hexcode"
Tell me if it works
I try to create a TextBox with a little triangle at the top right corner. I don't really know how to achieve it. I tried to add a polygon to the textbox at this way:
<TextBox
x:Name="PartnerEmail"
TextWrapping="Wrap"
MaxLength="50"
Grid.Column="1"
Grid.Row="12"
Margin="5,1,0,1" >
<TextBox.Style>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
But obviously it's not gonna work because I override the default template, so after this, all I have is a polygon and the textbox disappears. Can anyone have a good solution for this?
You are on the right track, but are working a bit too hard...
The thing to keep in mind about UI elements in WPF is that they work in layers. Think of elements as a composite of smaller items that you want to stack in a 3-D space. You aren't just working in a 2 dimensional drawing space anymore like a GDI rendering space of WinForms.
So lets logically think about what you want to do here. Lets try to achieve several goals in our solution:
Lets make a control template that will allow us to reuse our newly minted control.
Lets make the control completely portable in 3 dimensional space i.e. no use of raster images that will distort if we resize our control - lets stick to geometry only for drawing.
Lets make it easy to decide how large to make the triangle in the corner.
Lets decide to allow easy modifications for later, such as triangle placement (you want to change its location), hit testing (should it be part of the text surface or the border?), color (again, border or text?), etc.
Ok, to solve this, I alluded to the idea of objects in layers. Lets divide our drawing surface into a grid:
That means we want to use a Grid control. We want to define two rows and two columns, and we want to TextBox to cover all 4 cells. We will make sure to set the Rowspan and Columnspan to fill the grid.
We will then add a 2nd item, our Polyline triangle to row 1 column 1, and add it after the text box. That way it's Z-order will be on top.
Here then is the control template:
<Window.Resources>
<Style x:Key="TriangleTextBox" TargetType="{x:Type TextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10"/>
<RowDefinition Height="6*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6*" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<TextBox Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Margin="0,0,0,0" Text="{TemplateBinding Text}" BorderThickness="1"/>
<Polygon Grid.Row="0" Grid.Column="1" Points="0,0 10,0 0,10 0,0" Fill="Black" FlowDirection="RightToLeft"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Note that we set the key to "TriangleTextBox".
Now its just a simple matter of using our control template as follows:
<Grid>
<TextBox Style="{StaticResource ResourceKey=TriangleTextBox}" Width="100" Height="20"/>
</Grid>
And there you have it:
You can expand on this from there.
You are essentially replace the entire textbox by nothing but a triangle. You should copy the base template, and modify it from there:
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<!--<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>-->
<Grid>
<Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
As for the template itself, you get it from microsoft, or via visual studio.
Create a user (composite) control which would have the polygon (drawn last) to overlay a textbox in the corner as needed. Usage of a Canvas control for specific placement or within a Grid for general placement in the control.
Here is where I had to put a search icon over a text field in a grid. I set the ZIndex as needed.
Code
<TextBox Grid.ColumnSpan="2"
Panel.ZIndex="0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
<Image Grid.Column="1" Source="../Assets/Search.png"
Panel.ZIndex="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Stretch="Uniform"/>
I have a Button that I am adding an image via Window.Resources.
XAML for the Window.Resources
<Window.Resources>
<ImageBrush x:Key="MyResource" ImageSource="Pics\Button.png" />
</Window.Resources>
And the XAML for the Button,
<Button Name="Button1" Height="25" Grid.Column="0"
Grid.Row="0" Background="{StaticResource MyResource}" Click="Button1_OnClick" > stuff
</Button>
The problem I am getting is that the image disappears when you mouse-over the button. I tried quite a few things ,but I just can't stop this behavior. I still want the button to act as a normal button would on mouse-over with a color change to show that you are over it, but I have no idea how to go about this?
EDIT: The reasson I went with ImageBrush was so I could conform the image to the button.
EDIT 2: I need the image to change color like a normal mouse over would do.
Try this :
<Button Name="Button1" Height="25" Grid.Column="0"
Grid.Row="0" Click="Button1_OnClick">
<Border Background="{StaticResource MyResource}">
<TextBlock Text="stuff"/>
</Border>
</Button>
You could also set the Background based on MouseOver via the Button's ControlTemplate. This makes things much cleaner, as it's done all in xaml.
<Window.Resources>
<ImageBrush x:Key="MyResource" ImageSource="Pics\Button.png" />
<ImageBrush x:Key="MyResource2" ImageSource="Pics\Button2.png" />
<Style x:Key="MyButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Background" Value="{StaticResource MyResource}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="0"
Background="Transparent">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource MyResource}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="{StaticResource MyResource2}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Button Name="Button1"
Style="{StaticResource MyButtonStyle}"
Height="25"
Grid.Column="0"
Grid.Row="0"
Click="Button1_OnClick">stuff</Button>
OK, I figured this out,
I found this effective as it also shows you are over the button by reducing the opacity and this way only requires XAML, so it is much cleaner.
<Style x:Key="OpacityButton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" BorderThickness="1"
Padding="2,2,2,2" BorderBrush="#FFEE82EE"
Background="{TemplateBinding Background}"
CornerRadius="5">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This next way uses code behind the XAML and is not a clean as using just XAML ,but I am guessing there may be times when you might want to use code behind, so I am going to show this way as well.
<Style x:Key="TransparentStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then in the Button I added MouseEnter and MouseLeave events to change the image source,
<Button Name="Button1" Style="{StaticResource TransparentStyle}" Grid.Column="0" Grid.Row="0" Height="50" Width="70" Click="Button1_OnClick" MouseEnter="Button1_OnMouseEnter" MouseLeave="Button1_OnMouseLeave">
<StackPanel Orientation="Horizontal">
<Image x:Name="image4" Stretch="UniformToFill" />
</StackPanel>
</Button>
Then in the code behind,
private void Button1_OnMouseEnter(object sender, MouseEventArgs e)
{
string imageSource = #"c:\users\user\documents\visual studio 2015\Projects\TestAppForXAML\TestAppForXAML\Pics\1211794133.png";
image4.Source = new ImageSourceConverter().ConvertFromString(imageSource) as ImageSource;
}
private void Button1_OnMouseLeave(object sender, MouseEventArgs e)
{
string imageSource = #"c:\users\user\documents\visual studio 2015\Projects\TestAppForXAML\TestAppForXAML\Pics\1313321102.jpg";
image4.Source = new ImageSourceConverter().ConvertFromString(imageSource) as ImageSource;
}
This switches between two images when the mouse is enters or leaves ,giving you the effect that a normal mouse over gives you.
I want to make my custom tab control style. Headers should be on the left side and the content on the right side. Just like the standard styles can do it:
The selected element on the image above is the grid inside the active item. As you can see, it perfectly aligns next to the headers.
This is my design. The selected element is also the grid inside the active item, but it is just behind the headers instead of next to them. How can I align this grid next to the headers?
These are my styles for the tab item and tab control:
<Style TargetType="{x:Type TabControl}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabPanel
Name="HeaderPanel"
Grid.Row="0"
Panel.ZIndex="1"
Margin="0"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="AliceBlue" />
<Border
Name="Border"
Grid.Row="1"
BorderThickness="0"
KeyboardNavigation.TabNavigation="Local"
KeyboardNavigation.DirectionalNavigation="Contained"
KeyboardNavigation.TabIndex="2" >
<ContentPresenter
Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Margin="0"
Padding="10,4,4,4"
Background="Transparent"
Height="30"
Width="Auto"
BorderThickness="0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Left"
ContentSource="Header"
RecognizesAccessKey="True"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Panel.ZIndex" Value="100" />
<Setter TargetName="Border" Property="Background" Value="#FFFFFFFF" />
<Setter TargetName="Border" Property="BorderBrush" Value="#FF4576a9"></Setter>
<Setter TargetName="Border" Property="BorderThickness" Value="6, 0, 0, 0"></Setter>
<Setter TargetName="Border" Property="Padding" Value="4"></Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="Yellow" />
<Setter Property="Foreground" Value="Orange" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thank you.
In your Custom Template, you need to set Grid.Column instead of Grid.Row since your grid is now 2 cols/1 row instead of 1 col/2 rows
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid ...>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TabPanel
Name="HeaderPanel" Grid.Column="0" ... />
<Border Name="Border" Grid.Column="1" ... >
<ContentPresenter ... />
</Border>
</Grid>
</ControlTemplate>
You need not to create a custom control. You can use TabStripPlacement property of tabcontrol to achieve this functionality.
<TabControl TabStripPlacement="Left">
<TabItem Header="Tab1">
</TabItem>
<TabItem Header="Tab2">
</TabItem>
</TabControl>
You can refer http://www.wpf-tutorial.com/tabcontrol/tab-positions/ or https://msdn.microsoft.com/en-us/library/system.windows.controls.tabcontrol.tabstripplacement(v=vs.110).aspx
So I have a TabControl that normally resides inside a TabItem. I would like to put that tab control inside a StackPanel so I can add some content above the TabControl. However, as soon as I put the TabControl inside a StackPanel the application stops working -- there is a memory leak somewhere and if I look at my process in Windows Task Manager it just keeps using more and more memory until it needs shut down. My .xaml file is pretty straightforward:
<TabControl Name="tabControlOuter" Margin="0,20,0,0" Background="#222222" >
<TabItem>...</TabItem>
<TabItem>...</TabItem>
<TabItem Header="Something" Name="something">
<TabControl Name="tabControlInner" Style="{StaticResource TabControlStyle1}"/>
</TabItem>
And my tab control style:
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="4,4,4,4"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="Black"/>
<Setter Property="Background" Value="#222222"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="ctlgrid" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
</Grid.RowDefinitions>
<Grid Panel.ZIndex="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<WrapPanel x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Background="#666666" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<DockPanel Width="300" x:Name="SearchDock" Background="#666666" Grid.Column="1" Height="65">
<Border BorderBrush="White" BorderThickness="1,0,1,0" HorizontalAlignment="Right" Margin="0,0,10,0"></Border>
<Label x:Name="searchStat" Height="30" DockPanel.Dock="Bottom" Foreground="White"></Label>
<TextBox x:Name="Search" Margin="0,0,10,0" Width="150" Height="30" DockPanel.Dock="Left" />
<Button ToolTip="Search" Width="35" Height="30" Padding="5,5,5,2" Margin="10,0,-30,0" Click="search_logs" DockPanel.Dock="Left" >
<Image Source="/Images/mglass.png" />
</Button>
<Button ToolTip="Next Search Result" Margin="0,0,20,0" Width="30" Height="30" Content="Next" Click="next_result" DockPanel.Dock="Right">
</Button>
<Button ToolTip="Previous Search Result" Margin="30,0,0,0" Width="30" Height="30" Content="Prev" Click="prev_result" DockPanel.Dock="Right">
</Button>
</DockPanel>
</Grid>
<Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now the problem is if I throw a StackPanel around my inner tab control things go south fast
<TabItem Header="Something" Name="something">
<StackPanel>
<TabControl Name="tabControlInner" Style="{StaticResource TabControlStyle1}"/>
<StackPanel>
</TabItem>
I`m adding tab items to my tab control programatically as such below:
TabControl itemsTab = (TabControl)this.FindName("tabControlInner");
itemsTab.Items.Clear();
TabItem setThistab = (TabItem)this.FindName("something");
setThistab.IsSelected = true;
foreach (CustomItem ale in my_collection)
{
TabItem newTab = new TabItem();
FrameDisplayTab ftab1 = new FrameDisplayTab();
ftab1.MyDatagrid.ItemsSource = ale.logentries;
newTab.Content = ftab1;
newTab.Header = ale.name;
itemsTab.Items.Add(newTab); <-- this is where I get into trouble from the stack pane. Everything works fine if my inner tab control is not in a stack panel or if I omit this line
}
Can someone see what is going on?? There are no exceptions being thrown anywhere.
For anyone who encounters this problem, it looks like the StackPanel was the issue. It seems that unless you specify a width and height on the StackPanel both it and its children will have a height and width of NaN which was causing the issue. Since I want the Height and Width to be 'Stretch,' I couldn`t use the StackPanel.
To resolve this, I changed from StackPanel to DockPanel. Problem solved