I have this style:
<Style x:Key="RadioButtonList" TargetType="{x:Type ListBox}">
<!-- ControlTemplate taken from MSDN http://msdn.microsoft.com/en-us/library/ms754242.aspx -->
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="80"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2">
<ScrollViewer
Margin="0"
Focusable="false">
<StackPanel Margin="2" IsItemsHost="True" />
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Border" Property="Background" Value="Transparent" />
<Setter TargetName="Border" Property="BorderBrush" Value="Transparent" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border Name="theBorder" Background="Transparent">
<RadioButton Focusable="False"
IsHitTestVisible="False"
IsChecked="{TemplateBinding IsSelected}">
<ContentPresenter />
</RadioButton>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
Used as this :
<ListBox
Grid.Column="2"
Style="{StaticResource RadioButtonList}"
ItemsSource="{Binding ModosConsultaSaldos}"
DisplayMemberPath="Description"
SelectedItem="{Binding ModoConsultaSaldos,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
Shows something like this:
But now I want to add a Title using the same Style,
Is this posible? How ?
This could be done in a number of ways. The easiest is simply to stick a label in front of the ListBox in the XAML whenever you use it. But if you want to enforce a consistent style, you'll want something better than that.
We could add properties to ListBox by writing a subclass of ListBox that adds a Header property (I'm going to call it Header instead of Title because that's what a built-in WPF control would call it).
But a slightly more flexible option is to write the Header property as an attached property. We'll also throw in a HeaderTemplate attached property as well, so you can style the header content appropriately. This is common WPF practice in controls that have headers, such as MenuItem or GroupBox. Those WPF controls have HeaderTemplateSelector and HeaderStringFormat properties as well; I'll leave those as an exercise for the student.
First, the attached properties: This is all boilerplate except for the names and types.
public static class ListBoxEx
{
public static Object GetHeader(ListBox obj)
{
return (Object)obj.GetValue(HeaderProperty);
}
public static void SetHeader(ListBox obj, Object value)
{
obj.SetValue(HeaderProperty, value);
}
public static readonly DependencyProperty HeaderProperty =
DependencyProperty.RegisterAttached("Header", typeof(Object), typeof(ListBoxEx),
new FrameworkPropertyMetadata(null) { AffectsMeasure = true, AffectsParentMeasure = true });
public static Object GetHeaderTemplate(ListBox obj)
{
return (Object)obj.GetValue(HeaderTemplateProperty);
}
public static void SetHeaderTemplate(ListBox obj, Object value)
{
obj.SetValue(HeaderTemplateProperty, value);
}
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.RegisterAttached("HeaderTemplate", typeof(Object), typeof(ListBoxEx),
new FrameworkPropertyMetadata(null) { AffectsMeasure = true, AffectsParentMeasure = true });
}
Now we'll add these to the Template:
...
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border
Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="2"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ContentControl
Content="{TemplateBinding local:ListBoxEx.Header}"
ContentTemplate="{TemplateBinding local:ListBoxEx.HeaderTemplate}"
/>
<ScrollViewer
Margin="0"
Focusable="false"
Grid.Row="1"
>
<StackPanel Margin="2" IsItemsHost="True" />
</ScrollViewer>
</Grid>
</Border>
And we'll give your Style another setter, to create a default header template that does the underlining you had in your screenshot:
<Setter Property="local:ListBoxEx.HeaderTemplate">
<Setter.Value>
<DataTemplate>
<Label
Content="{Binding}"
BorderBrush="Black"
BorderThickness="0,0,0,1"
HorizontalAlignment="Left"
/>
</DataTemplate>
</Setter.Value>
</Setter>
And we use it like this:
<ListBox
Style="{StaticResource RadioButtonList}"
ItemsSource="{Binding ModosConsultaSaldos}"
local:ListBoxEx.Header="Saldos"
...
/>
Related
I'm not sure if I'm missing something simple or not. I'm thinking maybe a binding needs to change possibly? Or maybe its not properly targeting the TextBox for the ErrorContent?
I think it's worth noting that neither example produces a binding error.
If I have the below XAML defined in my App.xml, when my field is validated, everything looks like it should be working, but the tooltip is not working because ErrorContent seems to be blank, if I change that binding in the tooltip to "Test" the tooltip shows "Test".
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<Image
Height="24"
Margin="-28,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
DockPanel.Dock="Right"
Source="/Resources/error-96.png"
ToolTip="{Binding /ErrorContent}" />
<AdornedElementPlaceholder />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If I add to that same XAML some triggers to set the border colors etc, the tooltip then magically starts working, seen below.
<Style BasedOn="{StaticResource DefaultTextBoxStyle}" TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border
x:Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True"
UseLayoutRounding="True">
<ScrollViewer
x:Name="PART_ContentHost"
Focusable="false"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Trigger.Setters>
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="3" />
</Trigger.Setters>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Validation.HasError" Value="false" />
<Condition Property="IsMouseOver" Value="true" />
</MultiTrigger.Conditions>
<MultiTrigger.Setters>
<Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
</MultiTrigger.Setters>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="border" Property="Opacity" Value="0.56" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<Image
Height="24"
Margin="-28,0,0,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
DockPanel.Dock="Right"
Source="/Resources/error-96.png"
ToolTip="{Binding /ErrorContent}" />
<AdornedElementPlaceholder />
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Incase you want to see the textbox binding, which works to show the ErrorTemplate.
<TextBox
Margin="0,2.5,2.5,2.5"
HorizontalAlignment="Stretch"
ui:ControlHelper.PlaceholderText="IPv4 Address"
ui:TextBoxHelper.IsDeleteButtonVisible="False"
Text="{Binding EditServerModel.IPAddress, ValidatesOnDataErrors=True}" />
My main reason for not wanting to use the second one is it replaces the template of the DefaultTextBoxStyle and breaks the placerholder text in the textboxes, along with some other special features, all I really want/need is the part that shows the error image with a tooltip.
Edit:
I'm using CommunityToolkit.MvvM. My models implement ObservableValidator, which implements INotifyDataErrorInfo. My properties in my models use DataAnnotation attributes such as [Required] and [RegularExpression]
An example:
public class ServerModel : ObservableValidator
{
private string _iPAddress;
[Required]
[RegularExpression(#"^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$", ErrorMessage = "Not a valid IPv4 address.")]
public string IPAddress
{
get => _iPAddress;
set
{
SetProperty(ref _iPAddress, value);
ValidateProperty(value);
}
}
}
Edit - Working answer:
I ended up copying the default style from the ModernWpf project and removing primitives:ValidationHelper.IsTemplateValidationAdornerSite="True" so that I could use my own validation template.
Try this binding:
ToolTip="{Binding [0].ErrorContent}"
It this doesn't work, the issue is related to the DefaultTextBoxStyle.
I've defined a ListViewItem style as shown below
<Style x:Key="BaseContentStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ListViewItem Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
FontWeight="{TemplateBinding FontWeight}">
<ContentPresenter/>
</ListViewItem>
<ControlTemplate.Triggers>
<Trigger Property="ItemsControl.AlternationIndex" Value="0">
<Setter Property="Background" Value="#ebebeb"/>
</Trigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Conference">
<Setter Property="Content" Value="{Binding Conference}"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Background" Value="#192942"/>
</DataTrigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Division">
<Setter Property="Content" Value="{Binding Division}"/>
<Setter Property="BorderBrush" Value="LightGray"/>
<Setter Property="BorderThickness" Value="1.5"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Background" Value="Transparent"/>
</DataTrigger>
<DataTrigger Binding="{Binding ListViewPosition}" Value="Team">
<Setter Property="ContentTemplate" Value="{StaticResource MyDataTemplate}"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I've defined my ListView as follows
<ListView ItemsSource="{Binding AmericanAthleticTeams}"
SelectedItem="{Binding Path=SelectedTeam, Mode=TwoWay}"
ItemContainerStyle="{StaticResource BaseContentStyle}">
This is the DataTemplate used for the ContentTemplate in the Style template
<DataTemplate x:Key="MyDataTemplate" >
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding Logo, Converter={StaticResource imageConverter}}"
RenderOptions.BitmapScalingMode="Fant"
Grid.Column="0"
Height="15"
Width="15"
HorizontalAlignment="Left"
Margin="5 0 0 0"/>
<TextBlock Text="{Binding Name}"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
</Grid>
</DataTemplate>
And here is the ViewModel serving as the View's DataContext
class NCAAFBTeamsViewModel : ViewModelBase
{
public List<NCAAFBTeamViewModel> AmericanAthleticTeams { get; set; }
private NCAAFBTeamViewModel team;
public NCAAFBTeamsViewModel(List<NCAAFBTeamViewModel> americanAthleticTeams)
{
AmericanAthleticTeams = americanAthleticTeams;
}
public NCAAFBTeamViewModel SelectedTeam
{
get { return team; }
set
{
team = value;
OnPropertyChanged();
}
}
}
The problem I'm running into is the binding for the SelectedItem property of the ListView doesn't work as intended. In particular, when I click on one of the displayed ListViewItems, the trigger isn't invoked for the bound SelectedTeam property in the ViewModel. I believe the issue resides with the ControlTemplate of my Style and that perhaps I'm not bubbling up high enough. I've scoured Google and unfortunately wasn't able to discover anything with regards to issues encountered with using a ControlTemplate to define ListViewItems and the impact it has on the SelectedItem property. Any help would be greatly appreciated!
I have a simple WPF Button as under:-
<Button Height="150" Width="145" Canvas.Top="8" Canvas.Left="9" x:Name="cmdButton_Template" Background="{Binding Button_BackGround}" Style="{StaticResource MyLocalButton}" Mouse.PreviewMouseUp="cmdButton_Template_PreviewMouseUp" >
<Label>
<ContentControl HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Height="131" Canvas.Left="10" Canvas.Top="10" Width="142" >
<Canvas x:Name="ContentCanvas">
<TextBlock Canvas.Left="{Binding Text_2_Left,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Canvas.Top="{Binding Text_2_Top,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Text="{Binding Text, ElementName=txtItem_Cat_Name2,UpdateSourceTrigger=PropertyChanged}" FontSize="{Binding Font_Size_2}" FontFamily="{Binding Font_Name_2}" Foreground="{Binding Font_Color_2}" FontStyle="{Binding ElementName=chkItalic_2,Path=IsChecked,Converter={StaticResource FIC}, UpdateSourceTrigger=PropertyChanged}" TextDecorations="{Binding Font_Underline_2,Converter={StaticResource FUC}}" FontWeight="{Binding Font_Bold_2,Converter={StaticResource FVT}}" x:Name="Button_Text_2" MouseLeftButtonUp="Button_Text_2_MouseLeftButtonUp" Grid.RowSpan="3"/>
</Canvas>
</ContentControl>
</Label>
</Button>
and i have a style like this in userControl.Resources like this:
<UserControl.Resources>
<Style x:Key="MyLocalButton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="borderZero" BorderThickness="0" BorderBrush="Black" Background="{TemplateBinding Background}" CornerRadius="{Binding AllCorners,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SomeButtonStyle" TargetType="Button">
<Setter Property="Background" Value="Black" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
This is my DataModel:
public class DM_ButtonSettings
{
public CornerRadius _AllCorners = new CornerRadius(10, 10, 10, 10);
public CornerRadius AllCorners
{
get { return _AllCorners; }
set
{
if (_AllCorners != value)
{
_AllCorners = value;
}
}
}
}
and this is my ViewModel:
public class DC_ButtonSettings:INotifyPropertyChanged
{
public CornerRadius _AllCorners = new CornerRadius(10, 10, 10, 10);
public CornerRadius AllCorners
{
get { return _AllCorners; }
set
{
if (_AllCorners != value)
{
_AllCorners = value;
RaisePropertyChangedEvent("AllCorners");
}
}
}
}
I have a ViewModel property named CornerRadius and i am trying to change the Radius of the button corners at runtime using that property by binding it to style in the local resoources of the user control.
I am passing an object of this ViewModel to the form where the Button lies,and am trying to change the Button corner radius by changing the CornerRadius programatically as per the program logic.Though the values in the ViewModel are getting changed,but the View is not getting updated.I know i am missing something very simple here,but am unable to figure out on my own.
How do i do it right?
I just removed your mode & updatesourcetrigger from the style. it's working for me.
<Style x:Key="MyLocalButton" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="borderZero" BorderThickness="2" BorderBrush="Black" Background="{TemplateBinding Background}" CornerRadius="{Binding AllCorners}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm using my own control template for the TabControl and TabItem in the application resource of my project.
In the template, the selected TabItem is colored depending on a property 'SelectedBrush' which returns a Brush. I would also like the Border of the Tab Control (boTabControl, the border around the content presenter) to do be the same color as the selected TabItem.
Is this a code thing, or can it be done in the application resource?
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TabPanel Grid.Row="0" Panel.ZIndex="1" Margin="0,3,0,0" IsItemsHost="True" Background="Transparent"/>
<Border x:Name="boTabControl" Grid.Row="1" BorderThickness="1,3,0,0" CornerRadius="0" Padding="0" Margin="0" BorderBrush="{DynamicResource SelectedBrush}">
<ContentPresenter ContentSource="SelectedContent" Margin="0"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="True">
<Setter TargetName="boTabControl" Property="BorderBrush" Value="{Binding SelectedBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="boTabControl" Property="BorderBrush" Value="Blue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TabItem}">
<Setter Property="IsTabStop" Value="False"/>
<Setter Property="FontSize" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="Panel" Background="Transparent">
<Border x:Name="Border" Margin="0,0,-3,0" BorderThickness="1,1,1,0" CornerRadius="10,30,0,0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" ContentSource="Header" Margin="10"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
<Setter TargetName="Border" Property="Background" Value="{Binding SelectedBrush}" />
<Setter Property="Foreground" Value="White" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
<Setter Property="FontWeight" Value="Normal" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Public ReadOnly Property SelectedBrush As Brush
Get
If Me.tcMain.SelectedItem Is Nothing Then
Return Brushes.Aquamarine
Exit Property
End If
Dim myTabItem As TabItem = Me.tcMain.SelectedItem
Dim myBrush As Brush = Brushes.Blue
Select Case myTabItem.Name
Case Me.tiSale.Name
myBrush = Brushes.Green
Case Me.tiReturn.Name
myBrush = Brushes.Red
Case Me.tiStock.Name
myBrush = Brushes.Black
Case Me.tiAdmin.Name
myBrush = Brushes.Purple
End Select
Return myBrush
End Get
End Property
here is an approach with an attached property SelectedBrush of type Brush
add Attached class to project (and make build):
public class Attached
{
public static DependencyProperty SelectedBrushProperty = DependencyProperty.RegisterAttached("SelectedBrush", typeof(Brush), typeof(Attached));
public static Brush GetSelectedBrush(DependencyObject obj)
{
return (Brush) obj.GetValue(SelectedBrushProperty);
}
public static void SetSelectedBrush(DependencyObject obj, Brush value)
{
obj.SetValue(SelectedBrushProperty, value);
}
}
then assign colors to each TabItem:
<TabControl>
<TabItem Name="tiSale" local:Attached.SelectedBrush="Green" Header="123"/>
<TabItem Name="tiReturn" local:Attached.SelectedBrush="Red" Header="abc"/>
<TabItem Name="tiStock" local:Attached.SelectedBrush="Black" Header="XYZ"/>
</TabControl>
change TabControl template to use Attached.SelectedBrush:
<Style TargetType="{x:Type TabControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TabPanel Grid.Row="0" Panel.ZIndex="1" Margin="0,3,0,0" IsItemsHost="True" Background="Transparent"/>
<Border x:Name="boTabControl" Grid.Row="1"
BorderThickness="1,3,0,0"
BorderBrush="{Binding Path=SelectedItem.(local:Attached.SelectedBrush), RelativeSource={RelativeSource TemplatedParent}}"
CornerRadius="0" Padding="0" Margin="0">
<ContentPresenter ContentSource="SelectedContent" Margin="0"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
to use the same brush for TabItem, change Background setter like this:
<Setter TargetName="Border" Property="Background"
Value="{Binding (local:Attached.SelectedBrush), RelativeSource={RelativeSource TemplatedParent}}" />
SelectedBrush property from code behind is not used here
I am currently working on a Plug-In for AutoCAD, scripting language is VB.net.
Basically I have a User Control which holds a TabControl, each TabItem is an object which just holds the TabItem.Header and TabItem.Content definition. The TabItems are generated dynamically through a xml file. As I am using MVVM this is all stored in an ObservableCollection which is bound to the TabControl items.
As I am fighting with MVVM a little bit and I am rather new to WPF I need a little guidance on the following task: Everything is working fine so far but the only problem I have is that I want a little button at the end of the visible TabItems. When I click on it I can switch through all the Tabs, doesn't matter if they are visible or not.
For a better undertstanding, this should be the desired result:
Image File
I just want a simple explanation on how to achieve that (all the samples on the net are rather complex to me). I tried it with a ScrollViewer, but the result is bad. Here is the current code:
TabControl Template:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<StackPanel>
<ScrollViewer HorizontalScrollBarVisibility="Disabled"
VerticalScrollBarVisibility="Visible">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
KeyboardNavigation.TabIndex="1"
Grid.Column="0"
Grid.Row="0"
Margin="2,2,2,0"
IsItemsHost="true" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</StackPanel>
<!--<Grid>
<Grid.RowDefinitions KeyboardNavigation.TabNavigation="Local">
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ScrollViewer>
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
</ScrollViewer>
</Grid>-->
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TabItem"
TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border"
Margin="0,-2,5,0"
Padding="0,1,0,1"
Height="55"
BorderBrush="{StaticResource TabItemActiveBorder}"
CornerRadius="0,5,5,0">
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="2,5,2,5"
RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="True">
<Setter Property="Panel.ZIndex"
Value="100" />
<Setter TargetName="Border"
Property="Margin"
Value="-1,-2,1,0" />
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemActiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsSelected"
Value="false">
<Setter Property="TextElement.Foreground"
Value="{StaticResource TabItemInactiveText}" />
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource TabItemInactiveBackground}" />
<Setter TargetName="Border"
Property="BorderThickness"
Value="0,1,1,1" />
</Trigger>
<Trigger Property="IsEnabled"
Value="False">
<Setter TargetName="Border"
Property="Background"
Value="{StaticResource InActiveControlBackGround}" />
<Setter TargetName="Border"
Property="BorderBrush"
Value="{StaticResource InActiveControlBackGround}" />
<Setter Property="Foreground"
Value="{StaticResource InActiveControlBackGround}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<ContentPresenter Content="{TemplateBinding Content}">
<ContentPresenter.LayoutTransform>
<RotateTransform Angle="270" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
mainWindow XAML excerpt:
<Grid Background="{StaticResource TabBackground}">
<Grid Margin="0,96,0,0">
<TabControl ItemContainerStyle="{StaticResource TabItem}"
TabStripPlacement="Right"
ItemsSource="{Binding loadedPalettes}"
Style="{StaticResource TabControl}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}">
<TextBlock.LayoutTransform>
<RotateTransform Angle="270" />
</TextBlock.LayoutTransform>
</TextBlock>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<UserControls:tabDataGrid />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
TabItem Class:
Private Property _Header As String
Public Property Header As String
Get
Return _Header
End Get
Set(value As String)
_Header = value
End Set
End Property
Private Property _Content As String
Public Property Content As String
Get
Return _Content
End Get
Set(value As String)
_Content = value
End Set
End Property
Thanks in advance!
I solved the problem by myself. Here is the working piece of template code:
<Style x:Key="TabControl"
TargetType="{x:Type TabControl}">
<Setter Property="Background"
Value="{StaticResource TabBackground}">
</Setter>
<Setter Property="BorderBrush"
Value="{StaticResource TabItemActiveBorder}">
</Setter>
<Setter Property="BorderThickness"
Value="0,1,1,0">
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ScrollViewer HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Grid.Column="1"
Grid.Row="0">
<TabPanel x:Name="HeaderPanel"
Panel.ZIndex="1"
Margin="0,2,2,2"
IsItemsHost="True"
Background="Transparent" />
</ScrollViewer>
<ContentPresenter x:Name="PART_SelectedContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"
ContentSource="SelectedContent" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>