On a WPF app, I got a Canvas object containing several Path object. I need to do things on click on those Path, things that would be in VM. There is no Command on Path, like Button for example. What is the best way to do that?
My solution so far is :
To create an MouseDown handler on the view code behind to catch my Path click
Send a message from here
Register to this message type on targeted VM in order to execute my business code.
It seems a bit overkill to me, what's your opinion? Do you see a more straitforward method?
Thanks a lot !
You can use Button with Path as Template:
<Button Command="{Binding MyCommand}">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Path ... />
</ControlTemplate>
</Button.Template>
</Button>
Just to add complementary infos about my last comment... The right way to position ItemTemplate is to style the ContentPresenter, within ItemsControl.ItemContainerStyle. Below you will find my finally working code :
<UserControl.Resources>
<Style x:Key="PathStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Path Data="{Binding Data}"
StrokeStartLineCap="Round"
Stretch="Fill"
StrokeEndLineCap="Round"
Stroke="{DynamicResource selectedZoneBorderColor}"
StrokeLineJoin="Round"
Width="{Binding Path=Width}"
Height="{Binding Path=Height}"
Fill="{DynamicResource selectedZoneColor}"
Panel.ZIndex="1"
StrokeThickness="3" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<ItemsControl Name="zonesContainer" ItemsSource="{Binding Zones}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Grid.Column="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ResourceKey=PathStyle}"
Command="{Binding ElementName=zonesContainer,
Path=DataContext.ActivateZone}"
CommandParameter="{Binding Id}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding Path=Left}" />
<Setter Property="Canvas.Top" Value="{Binding Path=Top}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
All this with corresponding VM exposing a ObservableCollection, and a Zone class exposing all inside props (Width, Height, Top, Left...).
You can detailled answer here
Related
I've binded a List from my code-behind to a ListBox but I'm having difficulty stylizing the look to get what I want. I'd like to show up to 8 images at once, but no more than that without scrolling down. When the window resizes, I would like the image sizes to scale with it but still have no more than 8 showing. Here's my current XAML:
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Center" VerticalAlignment="Top" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Here's a pic of what this XAML produces. As you can see the images are much too large and we only see the top half of the second row. If I mess around with ListBoxItem margin I can get them smaller but this isn't really ideal as it only works if the screen resolution stays the same.
Set your image dimensions to be the same and use a WrapPanel instead:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" Width="400" Height="400"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
Alternatively, if you want a fixed number of columns then don't specify image dimensions at all and instead use a UniformGrid:
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Margin="5" >
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
UPDATE: I'm at a bit of a loss now to understand exactly what it is you're trying to do, the images you're posting don't match your description. If you want the panels to be square, and the images to scale up to them uniformly with a thin border around them, then there are a few things you'll have to do:
1) change your ListBoxItem ControlTemplate to be a Border with a Transparent background and the ContentPresenter inside it. This will ensure that your yellow border doesn't fill the whole box, and that the rest of the box doesn't highlight when selected, but that you can still click anywhere on it to select it.
2) change your ItemTemplate to be a grid (so that it fills all available space) with a border centered in the middle of it with padding (so that you'll be able to see the yellow border when selected), then put your Image content inside that but wrap.
This should do the job:
<Style TargetType="{x:Type ListBox}" x:Key="PictureListBoxStyle">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid Margin="5">
<Border Padding="5" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="Transparent" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBoxItem}}" Value="True">
<Setter Property="Background" Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Image Source="{Binding}" Stretch="Uniform" />
</Border>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<UniformGrid Columns="3" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
</Style>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Border Background="Transparent">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If that still isn't it then you'll need to define your requirements more clearly.
You could use a UniformGrid as ItemsPanel with appropriate HorizontalAlignment and VerticalAlignment. Also remove the redundant Border element from the DataTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Width="200" Height="200" Margin="5" Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Update: In order to have the yellow selection border directly around the image, use a ListBoxItem Style like shown below. To have the images scaled to (a fraction of) the full ListBox width, add an appropriate ControlTemplate.
<ListBox ItemsSource="{Binding PictureImagesList}">
<ListBox.Template>
<ControlTemplate TargetType="ListBox">
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Auto">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ListBox.Template>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="4" HorizontalAlignment="Left" VerticalAlignment="Top"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Background" Value="LightGray" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}" >
<Grid Background="{TemplateBinding Background}">
<Border HorizontalAlignment="Center" VerticalAlignment="Center"
BorderThickness="5"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderBrush" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
I'm trying to create a custom tooltip. The problem is that I can not display the error text. This code works perfectly (a simple tooltip)
<Style TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Polygon Fill="Red"
Margin="0,2,2,0"
Points="10,10 10,0 0,0"
VerticalAlignment="Top"
HorizontalAlignment="Right"
ToolTip="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}">
</Polygon>
<AdornedElementPlaceholder x:Name="adorner" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
But this code, not work, not show the error
<Style TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Polygon Fill="Red"
Margin="0,2,2,0"
Points="10,10 10,0 0,0"
VerticalAlignment="Top"
HorizontalAlignment="Right">
<Polygon.ToolTip>
<ToolTip Content="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"
BorderThickness="1"
Foreground="White"
Background="Red" />
</Polygon.ToolTip>
</Polygon>
<AdornedElementPlaceholder x:Name="adorner" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
The Tooltip itself and the AdornedElementPlaceholder reside in different namescopes so binding using an ElementName won't work.
But you can set the Tag property of the Polygon to the ErrorContent and bind the Content property of the Tooltip to the Tag property of its PlacementTarget (which is the Polygon). This works:
<Style TargetType="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<Grid>
<Polygon Fill="Red"
Margin="0,2,2,0"
Points="10,10 10,0 0,0"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Tag="{Binding ElementName=adorner, Path=AdornedElement.(Validation.Errors).CurrentItem.ErrorContent}">
<Polygon.ToolTip>
<ToolTip Content="{Binding PlacementTarget.Tag, RelativeSource={RelativeSource Self}}"
BorderThickness="1"
Foreground="White"
Background="Red" />
</Polygon.ToolTip>
</Polygon>
<AdornedElementPlaceholder x:Name="adorner" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The call to (Validation.Errors)[0] will be troublesome as you are referencing a particular object from a list that will update and change therefore breaking the binding.
The first example where you use (Validation.Errors).CurrentItem. is more suitable as it matches your first implementation which works.
I ran into issues with this a few years back, basically never use an index in a binding unless you are absolutely 100% sure it will not change.
I have a ListBox that looks like this:
<ListBox Name="ListBoxUsers" ItemsSource="{Binding Path=TempObservableUsers, ElementName=MainWindow, NotifyOnSourceUpdated=True}" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden" />
This ListBox shows, as you can see, a list of users comming from an ObservableCollection called TempObservableUsers. This part works fine.
Each element of the list looks like this:
As you can see, I modified my ItempsPanelTemplate to look differently. Here I attach my code:
<Style TargetType="ListBox" x:Key="VerticalListBox">
<Setter Property="Margin" Value="0,0,10,0"></Setter>
<Setter Property="Background" Value="Transparent" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="BorderBrush" Value="{DynamicResource RegularBlue}" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Width" Value="450" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" Width="450" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Vertical" Width="450" Margin="0,5" >
<StackPanel Orientation="Horizontal" Background="{DynamicResource TransparentMainBlue}" >
<Image Width="70" Height="70" Margin="5" Source="../images/delete.png" />
<StackPanel Orientation="Vertical" Width="285" >
<StackPanel Orientation="Horizontal">
<Label Content="NAME:" FontWeight="Bold"/>
<Label Content="{Binding Path=Name, FallbackValue=Name}" Foreground="White" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="ID:" FontWeight="Bold"/>
<Label Content="{Binding Path=Identifier, FallbackValue=Identifier}" />
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Top">
<Image Source="../images/edit.png" Width="20" />
<Image Source="../images/detail.png" Width="20" />
<Image Source="../images/delete.png" Width="20" />
</StackPanel>
</StackPanel>
<Grid Height="30" Background="{DynamicResource RegularBlue}">
<Label Content="XXXX-XXXX-XXXX-XXXX" Foreground="White" HorizontalContentAlignment="Center" FontWeight="Bold" />
</Grid>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Ok, after that:
As you can see, each item contains some images on top right corner. I want each one to do its job: edit, more, delete...
So I need to bind each image click with the corresponding item on the ListBox.
How can I bind each image click to do the corresponding action (edit, update, delete) and with its corresponding item on the ListBox?
EDIT: Now my code looks like this for each item template:
<StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button Command="{Binding DataContext.DeleteCommand}" CommandTarget="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}" CommandParameter="{Binding}">
<Image Source="../images/delete.png" Width="20" />
</Button>
............
</StackPanel>
How to implement DeleteCommand?
PS: I'm not using MVVM pattern yet, as I'm not famliar to it. Only trying to bind that button commands i xaml directly from my ResourceDictionary.
If I were attempting to fulfil your requirements, then I would use Buttons with an Image inside instead of Images on their own. Next, I would use a form of RelayCommand to handle my ICommands in the view model. Using this method, passing the relevant item along to the ICommand is easy using the CommandParameter property:
<StackPanel Orientation="Horizontal" Margin="5" HorizontalAlignment="Right"
VerticalAlignment="Top">
<Button Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:ThisView}}}" CommandParameter="{Binding}">
<Image Source="../images/edit.png" Width="20" />
</Button>
<Button Command="{Binding DataContext.DetailCommand, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:ThisView}}}" CommandParameter="{Binding}">
<Image Source="../images/detail.png" Width="20" />
</Button>
<Button Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource
AncestorType={x:Type YourPrefix:ThisView}}}" CommandParameter="{Binding}">
<Image Source="../images/delete.png" Width="20" />
</Button>
</StackPanel>
In order for this to work, it presumes:
1) You have set the DataContext of your Window or UserControl to an instance of a class that has ICommand properties named EditCommand, DetailCommand and DeleteCommand.
2) You replace the XAML Namespace Prefix value of YourPrefix to your own valid prefix.
3) You replace the imaginary ThisView name of the view where this code will reside with the actual name of the Window or UserControl where you add this code, eg. MainWindow.
As for how to use RelayCommands, that is another question and goes against the single question, single problem ethos of Stack Overflow. However, there are many tutorials on this. Here are some to help you on your way:
If you've not used ICommands before, then the Commanding Overview page on MSDN is an invaluable resource and a good introduction to them.
You'll find dozens of useful posts by searching Stack Overflow for RelayCommand.
You can find a clear implementation of this class in the Implementation RelayCommand question on the Visual Studio Forum.
Since there is no command binding available for Image, I'll demo same using a Button appearing as in image
Start by writing a style for a button, to remove the original appearance and leave with only what i want to show ( image in this case)
<Style x:Key="simpleButton" TargetType="Button">
<Setter Property="Width" Value="70"/>
<Setter Property="Height" Value="70"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Then I'll define my datatemplate as
<DataTemplate>
<StackPanel Orientation="Vertical" Width="450" Margin="0,5" >
<StackPanel Orientation="Horizontal" Background="{DynamicResource TransparentMainBlue}" >
<Button Style="{StaticResource simpleButton}"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=LixtBox}}"
CommandParameter="{Binding}">
<Image Source="../images/delete.png"/>
</Button>
...
then I'll write a DeleteCommand in my view model an initialize it's implementation using SimpleCommand, RelayCommand etc.
public ICommand DeleteCommand { get; set; }
once this is all in place my button which is now showing an image will bind itself to the command and will push the current item as command parameter upon execution (which is click for button)
I am making a user control that is databound. The query results include a collection of objects (A) where A has a collction of other results (B). So A contains multilple B.
in the user control I want to represent the collection A as expanders and B as buttons inside of the expanders. This is what I got
<UserControl x:Class="GuideLib.ModuleControls.uclQuestions"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ItemsControl x:Name="ictlAnswers" ItemsSource="{Binding}" Background="Gray">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Expander ExpandDirection="Down" Background="DarkGray">
<Expander.Header>
<TextBlock Text="{Binding Path=Name}" Foreground="White"/>
</Expander.Header>
<ListBox x:Name="SubListBox" ItemsSource="{Binding Path=Question}" Background="Gray" Foreground="White" HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<Button Content="{Binding Path=Name}" Margin="10,2,2,2" HorizontalAlignment="Stretch" Tag="{Binding Path=ID}">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have multiple problems.
1: I can not get the buttons in the expanders to strech horizontally
2: How can I set the Tag property of the button to be the whole object of B
3: Why does the default mouseover effect still execute.
Thanks
Ok here goes:
1. You need to set HorizontalContentAlignment="Stretch" on the ListBox and on the StackPanel inside DataTemplate set Orientation="Vertical"
2. set Tag="{Binding .}" on the Button
3. Update your Button.Style to something like:
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background"
Value="Gray" />
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="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="Background"
Value="Orange" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
finally before you add Question 4. remember ListBoxItem has a Style of it's own. So to completely override the effect on MouseOver when not on the Button but in the "Item" you have to provide a custom Style for ListBox.ItemContainerStyle
Oh and Start Using Snoop. It helps you debug Layout issues. Think you would have been able to solve problem 1 with it cos it would have shown you that your ContentPresenter of ListBoxItem was using required Width and not Stretching.
Just from taking a quick look at it.. for question 2 try doing this:
<Button Content="{Binding Path=Name}" Margin="10,2,2,2" HorizontalAlignment="Stretch" Tag="{Binding}">
That should make it bind to the items in the ListBox.
Assume that I have 3 different tab items with browsers and i want all the tab to load and render at the same time once I open my window application.
My question: Is there any approach for every tabs that can render in parallel or thread?
You can hack it using a custom template that uses a ListBox instead of the default ContentPresenter:
<TabControl>
<TabItem Header="A">
<WebBrowser Source="http://www.google.com/" />
</TabItem>
<TabItem Header="B">
<WebBrowser Source="http://www.bing.com/" />
</TabItem>
<TabItem Header="C">
<WebBrowser Source="http://www.yahoo.com/" />
</TabItem>
<Control.Template>
<ControlTemplate TargetType="TabControl">
<DockPanel>
<TabPanel IsItemsHost="True"
DockPanel.Dock="{TemplateBinding TabStripPlacement}" />
<ListBox ItemsSource="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Items}"
SelectedIndex="{TemplateBinding SelectedIndex}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter Content="{Binding Content}"
ContentTemplate="{Binding ContentTemplate}"
ContentTemplateSelector="{Binding ContentTemplateSelector}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Visibility"
Value="Hidden" />
<Style.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Visibility"
Value="Visible" />
</Trigger>
</Style.Triggers>
</Style>
</ItemsControl.ItemContainerStyle>
</ListBox>
</DockPanel>
</ControlTemplate>
</Control.Template>
</TabControl>
A Window can start in its own separate UI thread. But tabs will be rendered on the UI thread the current Window is started on.