I have a ListView. When I select a row I want that only one cell was selected not the whole row. How can I get this?
Here is my styles and templates.
<ListView x:Name="List"
ItemsSource="{Binding }"
ItemContainerStyle="{DynamicResource ListItemStyle}">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn HeaderContainerStyle="{StaticResource myHeaderStyle}"
Header="1"
CellTemplate="{StaticResource myCellTemplate1}">
</GridViewColumn>
<GridViewColumn Header="2"
HeaderContainerStyle="{StaticResource myHeaderStyle}"
HeaderTemplate="{StaticResource myHeaderTemplate}"
CellTemplate="{StaticResource cellTemplate2}">
</GridViewColumn>
<GridViewColumn Header="3"
HeaderContainerStyle="{StaticResource myHeaderStyle}"
HeaderTemplate="{StaticResource myHeaderTemplate}"
CellTemplate="{StaticResource cellTemplate3}" />
<GridViewColumn Header="4"
HeaderContainerStyle="{StaticResource myHeaderStyle}"
HeaderTemplate="{StaticResource myHeaderTemplate}"
CellTemplate="{StaticResource cellTemplate4}"/>
</GridView>
</ListView.View>
</ListView>
<Style x:Key="ListItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}" >
<Grid SnapsToDevicePixels="True" Margin="0" Width="410" x:Name="GridSmall">
<Border x:Name="Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="0" />
<GridViewRowPresenter x:Name="Rows" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Yellow"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="Black"/>
<Setter Property="Foreground" Value="Green"/>
</Trigger>
</Style.Triggers>
</Style>
<DataTemplate x:Key="myCellTemplate1">
<DataTemplate.Resources>
<local:NullIdConverter x:Key="NullIdConverterKey"/>
</DataTemplate.Resources>
<DockPanel x:Name="RR">
<TextBlock FontSize="18" x:Name="TxtBl"
HorizontalAlignment="Center"
Text="{Binding Path = Id}"/>
</DockPanel>
</DataTemplate>
Thanks.
If you're using .NET 3.5 SP1 or .NET 4, I'd suggest looking into the DataGrid rather than ListView.
I think it gives you much more flexibility over your data and has a property called SelectionUnit that you can set to "Cell" that gives you the functionality that you desire.
Unfortunately, I don't think there is an easy way to do the same with the ListView.
Well.....it isn't easy. Like Scott says you may have a lot easier life using SelectionUnit and SelectionMode in .Net 4 and its DataGrid control. But, if you want to do it like you started to then try this:
In XAML (I didn't do the whole thing as Template or a Style, just the one column to get it working) you need code such as this:
<GridViewColumn.CellTemplate>
<DataTemplate>
<Border Name="myOwnBorder" BorderBrush="Gray" BorderThickness="1,1,1,0" Margin="-6,0,-6,0">
<Grid Margin="6,0,6,0">
<TextBlock Text="{Binding}"/>
</Grid>
</Border>
</DataTemplate>
</GridViewColumn.CellTemplate>
...and then in the code behing (not good design practice but for the sake of demo) create a function such as:
static bool FindBorderInListView(DependencyObject dep, ListView listView,
out Border border, out ListViewItem lvItem)
{
border = null;
lvItem = null;
DependencyObject depObj = dep;
while (depObj != listView)
{
if (border == null && depObj is Border)
{
border = depObj as Border;
if (border.Name != "myOwnBorder")
{
border = null;
}
}
else if (depObj is ListViewItem)
{
lvItem = depObj as ListViewItem;
}
depObj = VisualTreeHelper.GetParent(depObj);
}
return border != null && lvItem != null;
}
and then call it from the PreviewMouseDown event of your ListView:
private void MyList_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Border border;
ListViewItem lvItem;
if (FindBorderInListView(e.OriginalSource as DependencyObject, this.MyList,
out border, out lvItem))
{
ItemContainerGenerator generator = this.MyList.ItemContainerGenerator;
int rowIndex = generator.IndexFromContainer(lvItem);
int columnIndex = Grid.GetColumn(border);
MessageBox.Show("Cell #:" + rowIndex + columnIndex);
}
}
Credit where credit is due, Josh Smith worked out how to do this back in about 2007 I think in a reply to an MSDN community question.
Good luck with it! I had to implement something similar in a DataGrid once too.
Related
Say I want to use RowDetailsTemplate in my WPF.
<Grid x:Name="LayoutRoot" Background="White">
<data:DataGrid x:Name="grdVwDetails" AutoGenerateColumns="False" RowDetailsVisibilityMode="Collapsed">
<data:DataGrid.RowDetailsTemplate>
<DataTemplate>
<data:DataGrid HeadersVisibility="None" ItemsSource="{Binding Path= Project}" AutoGenerateColumns="True">
</data:DataGrid>
</DataTemplate>
</data:DataGrid.RowDetailsTemplate>
<data:DataGrid.Columns>
<data:DataGridTemplateColumn>
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="+" Click="HandleExpandCollapseForRow"></Button>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTextColumn Header="EmployeeID" Binding="{Binding EmpID}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Name" Binding="{Binding Name}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Address" Binding="{Binding Address}"></data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
In code behind I use event to change the button appearance.
private void HandleExpandCollapseForRow(object sender, RoutedEventArgs e)
{
Button expandCollapseButton = (Button)sender;
DataGridRow selectedRow = DataGridRow.GetRowContainingElement(expandCollapseButton);
if (null != expandCollapseButton && "+" == expandCollapseButton.Content.ToString())
{
selectedRow.DetailsVisibility = Visibility.Visible;
expandCollapseButton.Content = "-";
}
else
{
selectedRow.DetailsVisibility = Visibility.Collapsed;
expandCollapseButton.Content = "+";
}
}
It seems work. My question is that I don't want to use +/- for button. I want to use different image for expand/collapse.
And do it should be done in xaml instead of code behind.
The entire project can be found at http://www.a2zmenu.com/Blogs/Silverlight/Collapse-RowDetailstemplate-on-clicking-again.aspx
That is for Silverlight, I use it for WPF.
You could replace the Button in the DataTemplate with a ToggleButton with a custom template:
<ToggleButton Width="50" Height="50">
<ToggleButton.Template>
<ControlTemplate TargetType="ToggleButton">
<Image x:Name="img" Source="plus.png" />
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter TargetName="img" Property="Source" Value="minus.png" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ToggleButton.Template>
</ToggleButton>
I have some trouble getting my cells to Wrap, they just go out of bounds, when I look at the visual tree I can see that inside the contentpresenter it sees a text block which I try to set as a style on the content presenter, but when I look at the properties it says no wrap.
I don't know how to do it with a data template, cause its an list of expando objects that is bound to the gridview, where the dynamic properties is bound by the column name. So I don't see how I could bind text="{binding dynamicproperty}. Therefore I tried to change it on the content presenter.
<Grid HorizontalAlignment="Center" Grid.Row="1">
<DataGrid HeadersVisibility="None"
ItemsSource="{Binding SheetData}"
Background="Transparent"
AutoGenerateColumns="False"
ColumnWidth="*"
IsHitTestVisible="False"
BorderThickness="0,2,0,0"
UseLayoutRounding="True"
BorderBrush="White"
RowBackground="Transparent"
MaxWidth="700"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalGridLinesBrush="White"
VerticalGridLinesBrush="White"
Behaviors:GridViewBindingBehavior.ColumnsCollection="{Binding ColumnData}"
VerticalAlignment="Top"
HorizontalContentAlignment="Left"
Width="auto">
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Margin="5,0" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=Item.RowIndex}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Padding" Value="8, 7"/>
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="Background" Value="#f1f2f4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter>
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" >
<Setter Property="TextWrapping" Value="WrapWithOverflow"/>
<Setter Property="Height" Value="auto"/>
<Setter Property="Width" Value="auto"/>
</Style>
</ContentPresenter.Resources>
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
</DataGrid>
</Grid>
Edit:
Since I don't think i am able to use a DataTemplate with the TextBlock within, due to the way i bind the columns, from my attached behavior, maybe there is a way to add the Text wrapping from code. I used the attached behavior from here.
Here is my attached behavior:
public class GridViewBindingBehavior
{
public static readonly DependencyProperty ColumnsCollectionProperty = DependencyProperty.RegisterAttached("ColumnsCollection", typeof(ObservableCollection<DataGridColumns>), typeof(GridViewBindingBehavior), new PropertyMetadata(OnColumnsCollectionChanged));
public static void SetColumnsCollection(DependencyObject o, ObservableCollection<ColumnDefinition> value)
{
o.SetValue(ColumnsCollectionProperty, value);
}
public static ObservableCollection<ColumnDefinition> GetColumnsCollection(DependencyObject o)
{
return o.GetValue(ColumnsCollectionProperty) as ObservableCollection<ColumnDefinition>;
}
private static void OnColumnsCollectionChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
DataGrid gridView = o as DataGrid;
if (gridView == null)
{
return;
}
gridView.Columns.Clear();
if (gridView.ItemsSource == null)
{
return;
}
ObservableCollection<ExpandoObject> objExpando = (ObservableCollection<ExpandoObject>)gridView.ItemsSource;
if (e.NewValue == null)
{
return;
}
var collection = e.NewValue as ObservableCollection<DataGridColumns>;
if (collection == null)
{
return;
}
foreach (var column in collection)
{
var gridViewColumn = GetDataColumn(column);
gridView.Columns.Add(gridViewColumn);
}
}
private static DataGridTextColumn GetDataColumn(DataGridColumns columnName)
{
var column = new DataGridTextColumn();
column.IsReadOnly = true;
column.Header = columnName.DisplayColumnName;
Binding binding = new Binding();
binding.Converter = new ColumnValueConverter();
binding.ConverterParameter = columnName.BindingPropertyName;
column.Binding = binding;
return column;
}
}
Edit 2:
I managed to get it to work with a value converter. The only thing is they way i find the actual row I am on is so ugly, is there a way to bind the datagrid to the second binding. I see the datagrid has CurrentColumn property, but i think that is for selections, and its null when inside the converter.
updated datagrid:
<DataGrid HeadersVisibility="None"
ItemsSource="{Binding SheetData}"
Background="Transparent"
AutoGenerateColumns="False"
ColumnWidth="*"
BorderThickness="0,2,0,0"
UseLayoutRounding="True"
BorderBrush="White"
RowBackground="Transparent"
MaxWidth="700"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalGridLinesBrush="White"
VerticalGridLinesBrush="White"
Behaviors:GridViewBindingBehavior.ColumnsCollection="{Binding ColumnData}"
VerticalAlignment="Top"
HorizontalContentAlignment="Left"
Width="auto">
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<TextBlock Margin="5,0" Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=Item.RowIndex}"/>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Padding" Value="8, 7"/>
<Setter Property="BorderThickness" Value="2" />
<Setter Property="BorderBrush" Value="White" />
<Setter Property="Background" Value="#f1f2f4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<TextBlock TextWrapping="WrapWithOverflow" >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource columnConver}">
<Binding Path="." />
<Binding RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}" Path="." />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.CellStyle>
</DataGrid>
Ugly value converter:
public class ColumnMultiValueConverter : IMultiValueConverter
{
private static int columnIndex = 0;
private static int lastCount = 0;
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var row = values[0] as IDictionary<string, object>;
if (row == null)
return row;
var datagrid = values[1] as DataGrid;
if (columnIndex >= datagrid.Columns.Count || lastCount != datagrid.Columns.Count)
columnIndex = 0;
var result = (row[datagrid.Columns[columnIndex].Header.ToString()]);
columnIndex++;
lastCount = datagrid.Columns.Count;
return (result as GridCell)?.Value?.ToString();
}
This maybe needs to be a new questions since the wrapping is done.
Just my code have become very ugly.
I have a problem.
In my WPF application, if i press a tabItem with middle mouse button, this tabItem should close. Just like in FireFox.
But I try to do this using MVVM, and i need to use commands. Also my tabItems are created dynamically.
Help me plz!
Thank you!
Create a DataTemplate for your tab items like this:
<DataTemplate x:Key="ClosableTabTemplate">
<Border>
<Grid>
<Grid.InputBindings>
<MouseBinding Command="ApplicationCommands.Close" Gesture="MiddleClick" />
</Grid.InputBindings>
<!-- the actual contents of your tab item -->
</Grid>
</Border>
</DataTemplate>
In your application window, add a the close command
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Close" Executed="CloseCommandExecuted" CanExecute="CloseCommandCanExecute" />
</Window.CommandBindings>
and finally assign the data template as item template to your tab control.
You could add a MouseBinding to some InputBindings perhaps?
Closing a TabItem (Not Selected) - TabControl
<TabControl x:Name="TabControlUser" ItemsSource="{Binding Tabs}" Grid.RowSpan="3">
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" BorderThickness="1,1,1,0" BorderBrush="Gainsboro" CornerRadius="4,4,0,0" Margin="2,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="10,2"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="LightSkyBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="GhostWhite" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabControl.ItemTemplate>
<!-- this is the header template-->
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}" FontWeight="ExtraBold" VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Image Source="/Images/RedClose.png" Width="22" Height="22" MouseDown="Image_MouseDown" HorizontalAlignment="Right" Margin="10 0 0 0"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<!-- this is the body of the TabItem template-->
<DataTemplate>
<UserControl Content="{Binding UserControl, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
C# Code - Image MouseDown Click Event
try
{
int matches = 0;
DependencyObject dependency = (DependencyObject)e.OriginalSource;
// Traverse the visual tree looking for TabItem
while ((dependency != null) && !(dependency is TabItem))
dependency = VisualTreeHelper.GetParent(dependency);
if (dependency == null)
{
// Didn't find TabItem
return;
}
TabItem selectedTabItem = dependency as TabItem;
var selectedTabContent = selectedTabItem.Content as MainWindowViewModel.TabItem;
foreach (var item in MainWindowViewModel.Tabs)
{
if (item.Header == selectedTabContent.Header)
{
matches = MainWindowViewModel.Tabs.IndexOf(item);
}
}
MainWindowViewModel.Tabs.RemoveAt(matches);
}
catch (Exception ex)
{
System.Windows.Application.Current.Dispatcher.Invoke((System.Action)(() => new View.MessageBox(ex.Message).ShowDialog()));
}
This event finds with the exact Mouse clicked position (as TabItem)and this will remove
MainWindowViewModel.Tabs.RemoveAt(matches); the TabItem(even if it is not selected).
I want to achieve the following behavior:
Depending on a value use a different datatemplate:
<DataTemplate x:Key="cardTemplate2">
<Border x:Name="container">
.....
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ShowSecondDT}" Value="True">
<Setter Property="Child" TargetName="container">
<Setter.Value>
<StackPanel Orientation="Vertical" >
</StackPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
The application fails claiming that Setter Property="Child" is null...
Another information is that this Datatemplate in the resource of a control: (devexpress gris)
<dxg:GridControl xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid"
x:Name="gridTitulaire" DataSource="{Binding Contacts}" Width="600" >
<dxg:GridControl.Resources>
<DataTemplate x:Key="cardTemplate2">
<Border x:Name="container">
<StackPanel Orientation="Horizontal" >
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding isTitulairePrincipal}" Value="True">
<Setter Property="Child" TargetName="container">
<Setter.Value>
<StackPanel Orientation="Vertical" >
</StackPanel>
</Setter.Value>
</Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</dxg:GridControl.Resources>
<dxg:GridControl.Columns>
<dxg:GridColumn FieldName="first_name"/>
<dxg:GridColumn FieldName="last_name"/>
</dxg:GridControl.Columns>
<dxg:GridControl.View>
<dxg:CardView x:Name="view" ShowGroupedColumns="True" CardTemplate="{DynamicResource cardTemplate2}" />
</dxg:GridControl.View>
</dxg:GridControl>
Any idea ?
Thanks
Jonathan
Define two separate data templates (call them CardTemplateV for the vertical one, and CardTemplateH for the horizontal one, for example), and set the CardTemplateSelector to a selector object that checks the discriminating field.
Example:
class MyTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var cardData = item as CardData;
if (cardData == null) return null;
var dataObject = cardData.DataContext as YourDataType;
if (dataObject == null) return null;
if (dataObject.isTitulairePrincipal)
return (DataTemplate)App.Current.FindResource("CardTemplateV");
else
return (DataTemplate)App.Current.FindResource("CardTemplateH");
}
}
In the XAML add the selector to the resource dictionary and reference it from the grid:
<Window.Resources>
<local:YourTemplateSelector x:Key="MyTemplateSelector"/>
</Window.Resources>
...
<dxg:CardView
x:Name="view"
ShowGroupedColumns="True"
CardTemplateSelector="{StaticResource MyTemplateSelector}"/>
...
I have a custom control that is derived from TabItem, and I want to databind that custom TabItem to a stock TabControl. I would rather avoid creating a new TabControl just for this rare case.
This is what I have and I'm not having any luck getting the correct control to be loaded. In this case I want to use my ClosableTabItem control instead of the stock TabItem control.
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True"
Controls:ClosableTabItem.TabClose="TabClosed" >
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type Controls:ClosableTabItem}" >
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
EDIT: This is what I ended up with, rather than trying to bind a custom control.
The "CloseCommand" im getting from a previous question.
<Style TargetType="{x:Type TabItem}" BasedOn="{StaticResource {x:Type TabItem}}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border
Name="Border"
Background="LightGray"
BorderBrush="Black"
BorderThickness="1"
CornerRadius="25,0,0,0"
SnapsToDevicePixels="True">
<StackPanel Orientation="Horizontal">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="20,1,5,1"/>
<Button
Command="{Binding Path=CloseCommand}"
Cursor="Hand"
DockPanel.Dock="Right"
Focusable="False"
Margin="1,1,5,1"
Background="Transparent"
BorderThickness="0">
<Image Source="/Russound.Windows;component/Resources/Delete.png" Height="10" />
</Button>
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
<Setter TargetName="Border" Property="BorderThickness" Value="1,1,1,0" />
<Setter TargetName="Border" Property="BorderBrush" Value="DarkBlue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
found a way,
derive a class from TabControl and override this function, in my case I want the items of the tab control (when bound) to be CloseableTabItems
public class CloseableTabControl : TabControl
{
protected override DependencyObject GetContainerForItemOverride()
{
return new CloseableTabItem();
}
}
HTH Someone
Sam
You don't want to set the DataType of the DataTemplate in this case. The value of the ItemTemplate property is used whenever a new item needs to be added, and in the case of a tab control it will be used to create a new TabItem. You should declare an instance of your class within the DataTemplate itself:
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" Controls:ClosableTabItem.TabClose="TabClosed">
<TabControl.ItemTemplate>
<DataTemplate>
<Controls:ClosableTabItem>
<TextBlock Text="{Binding Path=Id}" />
</Controls:ClosableTabItem>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This will cause a new ClosableTabItem to be created whenever a new tab is added to the TabControl.
Update; From your comment, it sounds like that the ItemTemplate controls what is created within the TabItem, rather than changing the TabItem itself. To do what you want to do, but for a TreeView, you would set the HeaderTemplate. Unfortunately, I don't see a HeaderTemplate property of TabControl.
I did some searching, and this tutorial modifies the contents of the tab headers by adding controls to TabItem.Header. Maybe you could create a Style for your TabItems that would add the close button that your class is currently adding?