How to display a new control through trigger in WPF - wpf

Now I got a Grid and I'm trying to display a control, lets say a StackPanel in the grid to cover the origin content when the mouse enters. I put the StackPanel in the first row, made its ZIndex=10(greater than Grid) and property Visibility binding to the Grid's IsMouseOver property. This trick just has one defect: the StackPanel will influence the grid's layout. For example, if the StackPanel's width is up to 500 and the original Grid only 100, the Grid expands quietly annoyingly. Here is the XAML snippet
<Grid x:Name="FileControlGrid">
!--The StackPanel to display when mouse enters--!
<StackPanel Orientation="Vertical" ZIndex="10" Grid.Row="0"
Visibility="{Binding ElementName=FileControlGrid, Path=IsMouseOver, Converter={StaticResource MouseoverToVisibilityCvt}}">
<...>
</StackPanel>
!--Origin Content below, I need the stackpanel to cover the Image--!
<Image Grid.Row="0" Source="{Binding FilePath, Converter={StaticResource FileiconCvt}}" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Center" MaxWidth="100" MaxHeight="100" Margin="5"/>
<TextBlock Grid.Row="1" Margin="0,5" Text="{Binding FileName, Mode=TwoWay}" FontFamily="Times New Roman" HorizontalAlignment="Left" FontWeight="SemiBold" MaxWidth="150" TextTrimming="WordEllipsis" FontSize="14"/>
</Grid>
I attempted using the Trigger, but instead of setting simple properties, I've no idea how to generate a grandly new control in triggers. Anyone can help?
Images here

Didn't understand the reason why you want to display the StackPanel in MouseOver but here is a simple solution that should work :
Create two properties of Visibility ImageVisiable and StackPanelVisiable.
Connect both properties to the Controls
MouseEnter event Switch between them
Example :
Xaml Side :
<Grid x:Name="Mouse" MouseEnter="Mouse_MouseEnter" MouseLeave="Mouse_MouseLeave">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<!--The StackPanel to display when mouse enters-->
<StackPanel Orientation="Vertical" Visibility="{Binding StackPanelVisiable}" Grid.Row="0">
</StackPanel>
<!--Origin Content below, I need the stackpanel to cover the Image-->
<Image Grid.Row="0" Source="/Superman.jpg" Visibility="{Binding ImageVisiable}" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Center" MaxWidth="100" MaxHeight="100" Margin="5"/>
<TextBlock Grid.Row="1" Margin="0,5" Text="{Binding FileName, Mode=TwoWay}" FontFamily="Times New Roman" HorizontalAlignment="Left" FontWeight="SemiBold" MaxWidth="150" TextTrimming="WordEllipsis" FontSize="14"/>
</Grid>
View Model :
private Visibility m_stackVisibility;
private Visibility m_imageVisibility;
public MainVM()
{
m_stackVisibility = Visibility.Visible;
m_imageVisibility = Visibility.Hidden;
}
public Visibility StackPanelVisiable
{
get { return m_stackVisibility; }
set { SetProperty(ref m_stackVisibility , value); }
}
public Visibility ImageVisiable
{
get { return m_imageVisibility; }
set { SetProperty(ref m_imageVisibility, value); }
}
private void Mouse_MouseEnter(object sender, MouseEventArgs e)
{
((MainVM)this.DataContext).StackPanelVisiable = Visibility.Hidden;
((MainVM)this.DataContext).ImageVisiable = Visibility.Visible;
}
private void Mouse_MouseLeave(object sender, MouseEventArgs e)
{
((MainVM)this.DataContext).ImageVisiable = Visibility.Hidden;
((MainVM)this.DataContext).StackPanelVisiable = Visibility.Visible;
}
Hope it helped
Asaf

Related

How to make tooltip appear at fixed position (in this case: bottom left corner of page)

I have several items (in the form of rectangles) inside a "Carousel" (which again is basically just a fancy PathListBox)
When the mouse hovers over one of those rectangles, a tooltip with some information appears. The look of the rectangles is determined by a DataTemplate. The beginning of the xaml of this DataTemplate is displayed here:
<Carousel:CarouselControl.DataTemplateToUse>
<DataTemplate>
<Grid ShowGridLines="True">
<Grid.ToolTip>
<ToolTip Placement="Right"
PlacementRectangle="50,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false"
PlacementTarget="{Binding ElementName=Box512}"
>
<BulletDecorator>
<TextBlock Text="{Binding Text}"/>
</BulletDecorator>
</ToolTip>
</Grid.ToolTip>
//further xaml code defining the DataTemplate
Just for completeness, this is the xaml for "Box512":
<Border x:Name="Box512" Grid.Row="2" Grid.Column="1" Grid.RowSpan="4"
Grid.ColumnSpan="2" BorderThickness="0" Opacity="0.5">
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="Resources/Box512.ico"/>
</Style>
</Image.Style>
</Image>
</Border>
The tooltip is supposed to be displayed at a fixed location in the bottom left corner of the page close to a XAML element with the name "Box512".
To this end I used the "PlacementTarget"-Property of the tooltip. I tried (as you can see in the code above):
PlacementTarget="{Binding ElementName=Box512}"
This didn't work. INstead of in the left bottom corner of the page, the tooltip was still displayed at the rectangle over which the mouse hovered. I then tried:
PlacementTarget="{x:Bind Box512}"
... this didn't work either.
So my question is: how can I make the tooltip appear at the same position near Box512 independent of which rectangle my mouse is hovering over?
****************************ADDITIONAL INFORMATION***********************
MainWindow.xaml:
<Carousel:CarouselControl x:Name="CarouselControl"
ScaleRange="1.0,1.0"
MaxNumberOfItemsOnPath="4"
SelectedItem="{Binding CurrentData,Mode=TwoWay}"
SelectionChanged="CarouselControl_SelectionChanged"
ItemsSource="{Binding GraphItems}"
CustomPathElement="{Binding ElementName=customPath}">
<Carousel:CarouselControl.DataTemplateToUse>
<DataTemplate>
with this line of code the text inside the tooltip would get displayed BUT
the tooltip would not be in the desired location:
<!--<Grid ShowGridLines="True">-->
with this line of code the tooltip is empty but the tooltip
is displayed in the desired location:
<Grid ShowGridLines="True" ToolTipService.PlacementTarget="{Binding
ElementName=Box512}">
<Grid.ToolTip>
<ToolTip Placement="Right"
PlacementRectangle="50,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false">
<BulletDecorator>
<BulletDecorator.Bullet>
<Ellipse Height="10" Width="20" Fill="Blue"/>
</BulletDecorator.Bullet>
<TextBlock Text="{Binding Text}"/>
</BulletDecorator>
</ToolTip>
</Grid.ToolTip>
//further xaml code defining the DataTemplate
</Grid>
</DataTemplate>
</Carousel:CarouselControl.DataTemplateToUse>
</Carousel:CarouselControl>
MainWindow.cs:
public partial class MainWindow : Window
{
///View Model for MainWindow.
private ViewModels.MainWindowVM mainViewModel = null;
public MainWindow()
{
InitializeComponent();
//Initialize View Model
mainViewModel = new ViewModels.MainWindowVM();
//Set it as Data Context
this.DataContext = mainViewModel;
//Close-Event bound
mainViewModel.RequestClose += delegate
(object sender, EventArgs e) { this.Close(); };
}
}
The GraphItems list is defined as a property of the MainViewModel:
private List<GraphNode> _GraphItems;
public List<GraphNode> GraphItems
{
get { return _GraphItems; }
private set
{
_cGraphItems = value;
this.RaisePropertyChangedEvent("GraphItems");
}
}
The "Text" Property is associated with the GraphNode class:
GraphNode.cs:
public class GraphNode : ObservableObject
{
///GENERAL INFORMATION
private string _Text;
public string Text {
get { return _Text; }
set { _Text = value; this.RaisePropertyChangedEvent("Text"); }
}
//more code
}
You should use the TooltipService to specify the placement target:
<TextBlock Text="Header" Grid.Row="0" Background="Green" Margin="0,0,0,0" ToolTipService.PlacementTarget="{Binding ElementName=Box512}">
<TextBlock.ToolTip>
<ToolTip Placement="Right"
PlacementRectangle="50,0,0,0"
HorizontalOffset="10"
VerticalOffset="20"
HasDropShadow="false"
>
<BulletDecorator>
<TextBlock Text="This is the tooltip text"/>
</BulletDecorator>
</ToolTip>
</TextBlock.ToolTip>
</TextBlock>

how to control opacity of descendant controls based on parent control's opacity ?

I have created a user control having grid and few controls inside grid. I have set Opacity to .1 of my parent grid and i want to set the descendant control's opacity to 1. Is is possible to do in XAML tree architecture ?
Here is my xaml code:
<Grid Name="busyIndicatorGrid" Visibility="Visible" Opacity=".2"
Background="DarkBlue" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel Orientation="Vertical" Opacity="1"
Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center">
<ProgressBar Name="progressBar" Foreground="White"
IsIndeterminate="True" MinWidth="100" Height="25" VerticalAlignment="Center"/>
<TextBlock Name="txtProgressText"
FontSize="40"
Margin="0,5,0,0"
Text="Please wait while application is being initialized."
TextAlignment="Left" TextWrapping="Wrap" />
</StackPanel>
</Grid>
Opacity is a property that will be propagated down the subtree.
If parent opacity is 0.5 and child opacity is 0.2 the parent will be drawn with 50% and child will be drawn with 20% of parent's 50%... Sort of like that just for better understanding... I hope you get me :)
Try this out and you will see:
<Grid Name="busyIndicatorGrid" Visibility="Visible" Opacity=".2">
<StackPanel Orientation="Vertical" Opacity="1" >
...
<Grid Name="busyIndicatorGrid" Visibility="Visible" Opacity=".2">
<StackPanel Orientation="Vertical" Opacity="0.5">
...
Those two will be drawn differently that means the children do no take the opacity value from its parent but instead calculate their own.
If you want to control how inner children are going to be drawn I would suggest to you to create an attached property that inherits its content down the VisualTree and when set to true it changes the opacity of its "underneathly" associated elements to 1 or to their previous old value.
Here is an example:
public static bool GetChangeOpacity(DependencyObject obj)
{
return (bool)obj.GetValue(ChangeOpacityProperty);
}
public static void SetChangeOpacity(DependencyObject obj, bool value)
{
obj.SetValue(ChangeOpacityProperty, value);
}
// Using a DependencyProperty as the backing store for ChangeOpacity. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ChangeOpacityProperty =
DependencyProperty.RegisterAttached("ChangeOpacity", typeof(bool), typeof(YourClass), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits, PropertyChangedCallback));
private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
FrameworkElement fe = dependencyObject as FrameworkElement;
if (fe != null && (bool)args.NewValue)
{
fe.Tag = fe.Opacity;
fe.Opacity = 1;
}
else if(fe != null && fe.Tag != null)
{
fe.Opacity = (double)fe.Tag;
}
}
Thank you guys for the valuable suggestions. But i have found way to resolve my issue by using brush for the parent grid control.
<Grid Name="busyIndicatorGrid" Visibility="Visible" Opacity=".2"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.Background>
<SolidColorBrush Color="DarkBlue" Opacity="0.2"/>
</Grid.Background>
<StackPanel Orientation="Vertical"
Background="Transparent" HorizontalAlignment="Center" VerticalAlignment="Center">
<ProgressBar Name="progressBar" Foreground="White"
IsIndeterminate="True" MinWidth="100" Height="25" VerticalAlignment="Center"/>
<TextBlock Name="txtProgressText"
FontSize="40"
Margin="0,5,0,0"
Text="Please wait while application is being initialized."
TextAlignment="Left" TextWrapping="Wrap" />
</StackPanel>
By doing so it will draw parent grid with the opacity i have defined in background property and it will have no effect on inside controls. all the controls will be drawn as usual without any opacity overriding effect which was set on parent grid.

Show and focus TextBox in DataTemplate

I have searched high and low, but I can't figure this one out. I am building a ListBox that has editable items. I have a DataTemplate for the ListBox.ItemTemplate that contains (among other things) a TextBlock and a TextBox. The TextBlock is always visible, and the TextBox is only visible after the user double-clicks on the TextBlock. When the user clicks another item in the list, the TextBox hides again to show the TextBlock. All of this works great. See my code:
XAML
<Window.Resources>
<local:GoalCollection x:Key="goals"/>
<DataTemplate x:Key="GoalItemTemplate" DataType="local:Goal">
<Grid>
<TextBlock Text="{Binding Title}"
MouseLeftButtonDown="TextBlock_MouseLeftButtonDown"
VerticalAlignment="Center"/>
<TextBox Name="EntryBox"
Text="{Binding Title}"
Visibility="Hidden"
BorderBrush="{x:Null}"
Padding="-2,0,0,0"
Panel.ZIndex="1"
Margin="-2,0,0,0"/>
</Grid>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ListBox Name="GoalsList"
ItemsSource="{Binding Source={StaticResource goals}}"
HorizontalContentAlignment="Stretch"
ItemTemplate="{StaticResource GoalItemTemplate}"
SelectionChanged="GoalsList_SelectionChanged" />
</Grid>
C#
public partial class MainWindow : Window
{
GoalCollection goals;
public MainWindow()
{
InitializeComponent();
}
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject { ... }
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
goals = (GoalCollection)Resources["goals"];
}
private void TextBlock_MouseLeftButtonDown(object sender,
MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
TextBlock tblk = sender as TextBlock;
if (tblk == null)
return;
TextBox tbx = ((Grid)tblk.Parent).FindName("EntryBox") as TextBox;
if (tbx == null)
return;
tbx.Visibility = Visibility.Visible;
Keyboard.Focus(tbx);
}
}
private void GoalsList_SelectionChanged(object sender,
SelectionChangedEventArgs e)
{
ListBoxItem lbi;
ContentPresenter cp;
DataTemplate dt;
TextBox tbx;
foreach (Goal item in e.RemovedItems)
{
lbi = (ListBoxItem)GoalsList.ItemContainerGenerator.
ContainerFromItem(item);
cp = FindVisualChild<ContentPresenter>(lbi);
dt = cp.ContentTemplate;
tbx = (TextBox)dt.FindName("EntryBox", cp);
if (tbx == null)
continue;
tbx.Visibility = Visibility.Hidden;
}
}
}
The problem that I'm having is that the TextBox immediately shifts focus back to the host ListBoxItem after the double-click. An additional (third) click is required to focus on the TextBox.
Tracing through this, I have found that the TextBox does indeed receive focus. But then it immediately loses it (try adding a handler for the TextBox.LostKeyboardFocus event and step through and out of the `TextBlock_MouseLeftButtonDown()' method). Any ideas?
Thanks.
My guess is that the click event is bubbling up to the ListBox and it's handling it by selecting the item.
Try adding this to your Click event handler (after Keyboard.Focus(tbx);)
e.Handled = true;
If you want to give focus to a child element, try the FocusManager.
<DataTemplate x:Key="MyDataTemplate" DataType="ListBoxItem">
<Grid>
<WrapPanel Orientation="Horizontal"
FocusManager.FocusedElement="{Binding ElementName=tbText}">
<CheckBox IsChecked="{Binding Path=Completed}" Margin="5" />
<Button Style="{StaticResource ResourceKey=DeleteButtonTemplate}"
Margin="5" Click="btnDeleteItem_Click" />
<TextBox Name="tbText"
Text="{Binding Path=Text}"
Width="200"
TextWrapping="Wrap"
AcceptsReturn="True"
Margin="5"
Focusable="True"/>
<DatePicker Text="{Binding Path=Date}" Margin="5"/>
</WrapPanel>
</Grid>
</DataTemplate>

Silverlight 4: how to show ToolTip on keyboard focus (revised)

My original question:
Is there an easy way for a ToolTip to be shown when an item gets keyboard focus, not just mouse over? We have a list of items with tooltips that users will probably tab through, and the desired behavior is for a tooltip to be shown then too.
Added example XAML. A HyperlinkButton with the Tooltip set is what needs the keyboard focus as well.
<DataTemplate x:Key="OfferingItemDT">
<HyperlinkButton Command="{Binding Path=NavigateToLinkCommand}" ToolTipService.ToolTip="{Binding Tooltip}">
<Grid x:Name="gOfferingButtonRoot" Width="275" MaxHeight="78" Margin="5,3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image x:Name="imgServiceOfferingIcon"
Grid.RowSpan="2"
VerticalAlignment="Top"
Source="{Binding Path=Image, Converter={StaticResource ByteArrayToImageConverter}}"
Stretch="UniformToFill"
Margin="2,10,0,0"
MaxHeight="32" MaxWidth="32"
/>
<TextBlock x:Name="txbOfferingTitle"
Grid.Column="1"
Grid.Row="0"
Text="{Binding Title}"
TextWrapping="Wrap"
Style="{StaticResource OfferingTileTitleText}"/>
<TextBlock x:Name="txbOfferingDesc"
Grid.Column="1"
Grid.Row="1"
Style="{StaticResource OfferingTileBodyText}"
Text="{Binding BriefDescription}" />
</Grid>
</HyperlinkButton>
</DataTemplate>
Updated:
Based on info in WPF: Show and persist ToolTip for a Textbox based on the cursor as well as Anthony's comments, I tried this code in the GotFocus eventhandler:
private void showTooltip(object sender, RoutedEventArgs e)
{
HyperlinkButton hb = new HyperlinkButton();
ToolTip ttip = new ToolTip();
hb = sender as HyperlinkButton;
ttip = ToolTipService.GetToolTip(hb) as ToolTip;
ttip.IsOpen = true;
}
This seems like it would work, but ttip is always null. Help?
"Easy" is subjective term. Yes its easy. On the same UI element on which you attach the ToolTip you can hook the GotFocus and LostFocus event handler the will use ToolTipService.GetToolTip to acquire the tooltip and the set IsOpen to true and false respectively.
The missing part is to define the tooltip in XAML so that we can access the Tooltip element.
<HyperlinkButton MouseLeftButtonUp="showTooltip">
<ToolTipService.ToolTip>
<ToolTip>
<TextBlock Text="My tooltip text"/>
</ToolTip>
</ToolTipService.ToolTip>
<!-- ... -->
</HyperlinkButton>
Code behind
private void showTooltip(object sender, RoutedEventArgs e)
{
FrameworkElement frameworkElement = (FrameworkElement)sender;
ToolTip tooltip = ToolTipService.GetToolTip(frameworkElement) as ToolTip;
if (tooltip != null)
{
tooltip.IsOpen = true;
frameworkElement.MouseLeave += new MouseEventHandler(frameworkElement_MouseLeave);
}
}
static void frameworkElement_MouseLeave(object sender, MouseEventArgs e)
{
FrameworkElement frameworkElement = (FrameworkElement)sender;
frameworkElement.MouseLeave -= new MouseEventHandler(frameworkElement_MouseLeave);
ToolTip tooltip = ToolTipService.GetToolTip(frameworkElement) as ToolTip;
if (tooltip != null)
{
tooltip.IsOpen = false;
}
}

How to access Button programatically if the button is inside using C#

I have few questions as I am usign XAML for the first time.
How do I use the button (BrowseButton) to browse a folder in Harddrive ?
In this case as the button is inside
Can I use the way I have shown below?
Actually first dockpanel will hold the image and some label and the other dockpanel will have tabcontrol in it.
If I have a tabcontrol, How can I add a listview which can increase the tabs during runtime.. and the listview should be available in the runtime also.
How to add a close("X") mark on the top of the tab to close the button
probably I asked a lot of questions, sorry :(
Please help
<Grid>
<DockPanel>
<StackPanel>
<Image Name="imgClientPhoto" HorizontalAlignment="Left" VerticalAlignment="Top" Width="auto" Height="auto" Grid.Column="0" Grid.Row="0" Margin="0"
Source="D:ehtmp_top_left.gif" MinWidth="450" MinHeight="100" Grid.IsSharedSizeScope="True">
</Image>
<Button x:Name="BrowseButton" Margin="0,13.638,30,14.362" Content="Browse" Click="BrowseButton_Click" HorizontalAlignment="Right" Width="111" />
<TextBox x:Name="txtBxBrowseTB" Margin="46,10,146,10" Text="TextBox" TextWrapping="Wrap" TextChanged="BrowseTB_TextChanged"></TextBox>
<Label HorizontalAlignment="Left" Margin="-14,22,0,10" Name="label1" Width="69.75" FontSize="13" VerticalContentAlignment="Top" HorizontalContentAlignment="Center">Path:</Label>
</Grid>
</GroupBox>
</Grid>
</StackPanel>
</DockPanel>
<DockPanel>
<StackPanel Margin="0,158,0,0" HorizontalAlignment="Left" Width="330" Height="557.5" VerticalAlignment="Top">
<TextBox Height="50" Name="textBox1" Width="240" Margin="0,35,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Right" />
<ListBox Height="470" Name="listBox1" Width="332" Background="LightGray" Margin="0,0,0,0" BorderBrush="IndianRed" BorderThickness="3" />
</StackPanel>
<TabControl Height="234" Name="tabControl1" Width="1035" Margin="0,0,0,0">
<TabItem Header="tabItem1" Name="tabItem1">
<Grid Height="144" />
</TabItem>
</TabControl>
</DockPanel>
</Grid>
1) The browse code should be something like this:
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.FolderBrowserDialog browse = new System.Windows.Forms.FolderBrowserDialog();
browse.RootFolder= Environment.SpecialFolder.MyDocuments;
browse.SelectedPath = "C:\\InitalFolder\\SomeFolder";
if (browse.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtBxBrowseTB.Text = browse.SelectedPath;
}
}
2) I have tried to simplify the xaml. Does this look like something you could go with?:
<Grid>
<Image Name="imgClientPhoto" Margin="0" Height="262" VerticalAlignment="Top" HorizontalAlignment="Left" ></Image>
<StackPanel VerticalAlignment="Stretch" >
<StackPanel VerticalAlignment="Top" Orientation="Horizontal" Height="30">
<Button Name="BrowseButton" Content="Browse" Click="BrowseButton_Click" HorizontalAlignment="Right" Width="111" />
<Label Name="label1" Width="69.75" FontSize="13" VerticalContentAlignment="Center" HorizontalContentAlignment="Right">Path:</Label>
<TextBox Name="txtBxBrowseTB" Width="200" Text="TextBox" VerticalContentAlignment="Center" TextWrapping="Wrap" TextChanged="BrowseTB_TextChanged"></TextBox>
</StackPanel>
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBox Height="50" Name="textBox1" />
<ListBox Height="470" Name="listBox1" Background="LightGray" Margin="0,0,0,0" BorderBrush="IndianRed" BorderThickness="3" MouseLeftButtonUp="listBox1_MouseLeftButtonUp">
<ListBoxItem>User1</ListBoxItem>
<ListBoxItem>User2</ListBoxItem>
<ListBoxItem>User3</ListBoxItem>
<ListBoxItem>User4</ListBoxItem>
</ListBox>
</StackPanel>
<TabControl Name="tabControl1" />
</StackPanel>
</StackPanel>
</Grid>
You can also have a close button in the tab item Header. As many of the content properties in xaml controls, the content can actually be controls, and not necessary just a text.
<TabControl Name="tabControl1" >
<TabItem Name="tabItem1" >
<TabItem.Header>
<StackPanel Orientation="Horizontal">
<Label>TabHeader1</Label>
<Button Height="20" Width="20" FontWeight="Bold" Click="CloseTabButton_Click">X</Button>
</StackPanel>
</TabItem.Header>
<Grid Height="144">
<ListView />
</Grid>
</TabItem>
</TabControl>
3) Here is how you would add the tabs in C# dynamically:
private void listBox1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//Get selected item
ListBoxItem item = (ListBoxItem)listBox1.SelectedItem;
string itemText = item.Content.ToString();
//Check if item is already added
foreach (TabItem tItem in tabControl1.Items)
{
if ((string)tItem.Tag == itemText)
{
//Item already added, just activate the tab
tabControl1.SelectedItem = tItem;
return;
}
}
//Build new tab item
TabItem tabItem = new TabItem();
tabItem.Tag = itemText;
//First build the Header content
Label label = new Label();
Button button = new Button();
label.Content = itemText;
button.Content = "X";
button.Height = 20;
button.Width = 20;
button.FontWeight = FontWeights.Bold;
button.Click += CloseTabButton_Click; //Attach the event click method
button.Tag = tabItem; //Reference to the tab item to close in CloseTabButton_Click
StackPanel panel = new StackPanel();
panel.Orientation = Orientation.Horizontal;
panel.Children.Add(label);
panel.Children.Add(button);
tabItem.Header = panel;
//Then build the actual tab content
//If you need only the ListView in here, you don't need a grid
ListView listView = new ListView();
//TODO: Populate the listView with what you need
tabItem.Content = listView;
//Add the finished tabItem to your TabControl
tabControl1.Items.Add(tabItem);
tabControl1.SelectedItem = tabItem; //Activate the tab
}
private void CloseTabButton_Click(object sender, RoutedEventArgs e)
{
//The tab item was set to button.Tag when it was added
Button button = (Button)sender;
TabItem tabItem = (TabItem)button.Tag;
if (tabItem != null)
{
button.Click -= CloseTabButton_Click; //Detach event handler to prevent memory leak
tabControl1.Items.Remove(tabItem);
}
}

Resources