Changing active tab's background in C# and XAML - c#

OK, I've searched everywhere and in every single link I go to my problem is explained with xaml code.
I want to change the active tab's background and foreground (not its content, but the upper part which you select in order to make active) in a WPF project, but I'm looking for the C# code. The code below doesn't work for me:
if (tabs[0].IsEnabled) tabs[0].Background = Brushes.Blue;
else tabs[0].Background = Brushes.Black;

Do it in XAML if you use WPF.
You can bind to the TabControl's property ItemsSource. Than just define a Styletrigger to change the Background

OK, thanks to Venson I've finally got it and just in case someone wants to know how it works:
<TabControl ItemsSource="{Binding tabs}" Height="68" HorizontalAlignment="Left" Margin="156,23,0,0" Name="tabControl1" VerticalAlignment="Top" Width="268">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Margin="0,0,-4,0"
Background="Black"
BorderBrush="Blue"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue"></Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Margin="0,0,-4,0"
Background="Green"
BorderBrush="Blue"
BorderThickness="1,1,1,1"
CornerRadius="2,12,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"
RecognizesAccessKey="True"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
This code goes in the <Grid>of the <Window> tags of the MainWindow.xaml and
public MainWindow()
{
testClass testObject = new testClass();
testObject.tabs = new List<TabItem>();
testObject.tabs.Add(new TabItem());
testObject.tabs.Add(new TabItem());
testObject.tabs[0].Header = "NO WAY";
testObject.tabs[1].Header = "ON WAY";
testObject.tabs[0].Content = "WHAT";
testObject.tabs[1].Content = "HELL";
InitializeComponent();
this.DataContext = testObject ;
}
class testClass
{
public List<TabItem> tabs { set; get; }
}
this goes into the MainWindow.xaml.cs file.
Please note: the colors are only for the test, don't judge me for the bad contrast chosen!
I don't know if it's possible not to use another class, though..

foreach(var tab in tabs)
{
tab.Background = tab.IsEnabled ? Brushes.Blue :Brushes.Black;
}
But you can handle state of tabcontrol on active tab changes and set backgrounds of deactivated and activated tabs.

Related

Removing full screen in xaml dynamically

This will probably be very simple for most of you, I am new to XAML and WPF.
I have an app that startes att full screen, I did this by adding
WindowState="Maximized"
WindowStyle="None"
I want to have a button that simply eliminates this part. I have a "Full screen" button in the xaml and by click he is calling a "FullScreen_Click" function in my code.
I just need to know what to write in the code that will eliminate the full screen if it is on full screen mode and restore it to full screen when it is not.
Try this:
private void FullScreen_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
This will toggle between WindowState.Maximized and WindowState.Normal each time the Button is clicked.
For a xaml only technique just for reference to see a xaml example in comparison (but I would do #mm8's route, it's simpler);
1. Bind your property to that of another like:
<Window WindowState="{Binding Tag, ElementName=toggleState}" .... />
2. Use a `ToggleButton` or similar control and `Triggers`
.
<!-- like this PoC -->
<Grid>
<Grid.Resources>
<Style x:Key="cwWindowState_PoC" TargetType="{x:Type ToggleButton}">
<Setter Property="Tag" Value="Maximized"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Grid>
<Border Background="{TemplateBinding Background}"/>
<ContentPresenter x:Name="MyContentPresenter"
Content="{TemplateBinding Tag}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Tag" Value="Normal" />
</Trigger>
<Trigger Property="IsChecked" Value="False">
<Setter Property="Tag" Value="Maximized" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<ToggleButton x:Name="toggleState" Content="Click Me"
Background="Green"
Style="{StaticResource cwWindowState_PoC}"/>
</Grid>
Could also use DataTrigger but that requires interaction triggers instead of just a property setter from a template.

Why does a custom control "ImageButton" not display it's image?

I'm writing an image button custom control with highlighting effects, based on MahApps' AccentedSquareButtonStyle. ImageButton.xaml:
<UserControl x:Class="NQR_GUI_WPF.ImageButton"
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"
xmlns:local="clr-namespace:NQR_GUI_WPF"
mc:Ignorable="d" >
<Button Style="{StaticResource AccentedSquareButtonStyle}" Background="Transparent" Foreground="Transparent" BorderThickness="0" Width="24" Height="24" TouchDown="Button_TouchDown">
<Grid Background="Transparent">
<ContentControl>
<ContentControl.Style>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Content" Value="{Binding Image, RelativeSource={RelativeSource TemplatedParent}}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsMouseOver}" Value="True" >
<Setter Property="Content" Value="{Binding HighlightedImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=IsPressed}" Value="True" >
<Setter Property="Content" Value="{Binding ClickedImage, RelativeSource={RelativeSource TemplatedParent}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
</Button>
ImageButton.xaml.cs:
namespace NQR_GUI_WPF
{
/// <summary>
/// Interaction logic for ImageButton.xaml
/// </summary>
public partial class ImageButton : UserControl
{
public static DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(Canvas), typeof(ImageButton));
public static DependencyProperty ClickedImageProperty = DependencyProperty.Register("ClickedImage", typeof(Canvas), typeof(ImageButton));
public static DependencyProperty HighlightedImageProperty = DependencyProperty.Register("HighlightedImage", typeof(Canvas), typeof(ImageButton));
static ImageButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ImageButton), new FrameworkPropertyMetadata(typeof(ImageButton)));
}
public Canvas Image
{
get { return (Canvas)base.GetValue(ImageProperty); }
set { base.SetValue(ImageProperty, value); }
}
public Canvas ClickedImage
{
get { return (Canvas)base.GetValue(ClickedImageProperty); }
set { base.SetValue(ClickedImageProperty, value); }
}
public Canvas HighlightedImage
{
get { return (Canvas)base.GetValue(HighlightedImageProperty); }
set { base.SetValue(HighlightedImageProperty, value); }
}
private void Button_TouchDown(object sender, TouchEventArgs e)
{
Keyboard.ClearFocus();
}
}
}
Example icon:
<Canvas x:Key="printIcon" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_printer_text" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
<Path Width="44" Height="45" Canvas.Left="16" Canvas.Top="17" Stretch="Fill" Fill="{Binding Source={x:Static prop:Settings.Default}, Path=theme, Converter={StaticResource idealForegroundConverter}}" Data="F1 M 25,27L 25,17L 51,17L 51,27L 47,27L 47,21L 29,21L 29,27L 25,27 Z M 16,28L 60,28L 60,51L 52,51L 52,46L 55,46L 55,33L 21,33L 21,46L 24,46L 24,51L 16,51L 16,28 Z M 25,39L 28,39L 28,52L 35,52L 35,59L 48,59L 48,39L 51,39L 51,62L 33,62L 25,54L 25,39 Z M 46,55L 38,55L 38,52L 46,52L 46,55 Z M 46,49L 30,49L 30,46L 46,46L 46,49 Z M 46,43L 30,43L 30,40L 46,40L 46,43 Z "/>
</Canvas>
The problem is that in MainWindow, after adding the images stored in App.xaml, the control is empty (no images are shown).
<local:ImageButton Image="{StaticResource printIcon}" HighlightedImage="{StaticResource printIconHighlighted}" ClickedImage="{StaticResource printIconClicked}" Grid.Column="1" HorizontalAlignment="Left" Height="46" Margin="36,10,0,0" VerticalAlignment="Top" Width="100"/>
I have tried binding the images directly into the control template, but without success (although in the control designer view the image is shown). Why aren't the control images displayed?
A UserControl isn't your best option for this. UserControls aren't meant for writing general-purpose WPF controls. You can do it, but it's not the simplest way. The simplest way is to subclass a regular control (often just ContentControl or HeaderedContentControl), then write a style and a template for it. Once you get this technique nailed down you can just bang 'em out as needed. Often you can just write a specialized template for an existing control, but in your case you do need your own subclass of Button.
I would write ImageButton as a subclass of Button, with the additional dependency properties pretty much as you've defined them, but I'd make them of type Object so a consumer can stuff anything in there that XAML can render. No reason not to give them all the rope they can use. And I'll use the Content property instead of the Image property, because that simplifies things.
If for some reason you have a requirement to prevent non-image content, you could use a more specialized content type than Object, but you didn't mention any particular reason for introducing that limitation.
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace NQR_GUI_WPF
{
/// <summary>
/// Interaction logic for ImageButton.xaml
/// </summary>
public class ImageButton : Button
{
public ImageButton()
{
TouchDown += ImageButton_TouchDown;
}
private void ImageButton_TouchDown(object sender, TouchEventArgs e)
{
Keyboard.ClearFocus();
}
#region Dependency Properties
public static DependencyProperty ClickedContentProperty = DependencyProperty.Register("ClickedContent", typeof(Object), typeof(ImageButton));
public static DependencyProperty HighlightedContentProperty = DependencyProperty.Register("HighlightedContent", typeof(Object), typeof(ImageButton));
public Object ClickedContent
{
get { return (Object)base.GetValue(ClickedContentProperty); }
set { base.SetValue(ClickedContentProperty, value); }
}
public Object HighlightedContent
{
get { return (Object)base.GetValue(HighlightedContentProperty); }
set { base.SetValue(HighlightedContentProperty, value); }
}
#endregion Dependency Properties
}
}
XAML resoure dictionary ImageButton.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nqrgui="clr-namespace:NQR_GUI_WPF"
>
<Style TargetType="{x:Type nqrgui:ImageButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type nqrgui:ImageButton}">
<Grid>
<ContentControl
Content="{TemplateBinding Content}"
x:Name="PART_Content"
/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter
TargetName="PART_Content"
Property="Content"
Value="{Binding HighlightedContent, RelativeSource={RelativeSource TemplatedParent}}"
/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter
TargetName="PART_Content"
Property="Content"
Value="{Binding ClickedContent, RelativeSource={RelativeSource TemplatedParent}}"
/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And here's how you'd use it:
<Window
...
xmlns:nqrgui="clr-namespace:NQR_GUI_WPF"
...
>
<!-- Or better yet, merge ImageButton.xaml in App.xaml so everybody can see it -->
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ImageButton.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
...
<!-- As noted, Content, HighlightedContent, and ClickedContent
can be images -- or also paths, text, ANYTHING XAML can render.
-->
<nqrgui:ImageButton
Content="Content"
HighlightedContent="Highlighted"
ClickedContent="Clicked"
/>
And you really can go absolutely berserk with the content:
<!-- Don't try this in a UI anybody will have to use! -->
<nqrgui:ImageButton
Content="Content"
ClickedContent="Clicked"
>
<nqrgui:ImageButton.HighlightedContent>
<StackPanel Orientation="Horizontal">
<Border
BorderBrush="Gray"
Background="GhostWhite"
BorderThickness="1">
<Path
Width="20"
Height="20"
Stroke="Black"
StrokeThickness="2"
Data="M 0,0 L 20,20 M 0,20 L 20,0"
Margin="2"
/>
</Border>
<nqrgui:ImageButton
Content="LOL"
ClickedContent="Don't Click Me, Bro!"
HighlightedContent="I heard you like buttons"
/>
</StackPanel>
</nqrgui:ImageButton.HighlightedContent>
</nqrgui:ImageButton>
You are using TemplateParent incorrectly
instead of this
{Binding Image, RelativeSource={RelativeSource TemplatedParent}}
it should be something like this
{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=ImageButton}, Path=Image}
I have done that like this below,
<Controls:MetroWindow.Resources>
<ImageBrush Stretch="Fill" x:Key="CloseImage" ImageSource="../images/Close.png" />
<ImageBrush x:Key="CloseImageRed" ImageSource="../images/CloseRed.jpg" />
</Controls:MetroWindow.Resources>
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="{StaticResource CloseImageRed}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
RecognizesAccessKey="True"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource CloseImage}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Button.Style>
</Button>
Have a look.
You are setting UserControl.Content to your customized Button, and I think what you want to be setting is UserControl.ContentTemplate.
From within .Content, there is no "TemplatedParent" to bind to. However if this were a Template, then TemplatedParent would point to the UserControl that the Template is defined for. In this case, it would refer to your ImageButton UserControl, which would correctly give you access to the Image properties.
<UserControl ..>
<UserControl.ContentTemplate>
<ControlTemplate>
<!-- TemplatedParent bindings should refer to UserControl from here -->
<Button ... />
</ControlTemplate>
</UserControl.ContentTemplate>
</UserControl>
This also allows you to write something like
<local:ImageButton Content="Some Text" />
without completely replacing your Button XAML code with a Text element containing "Some Text"
For an example, what you have right now would render as
<UserControl>
<Button /> <!-- Button is .Content, and can be replaced by XAML using the control -->
</UserControl>
While if it were a ContentTemplate, it would render as
<UserControl>
<Button> <!-- Button is ContentTemplate, so wraps any content given by external XAML -->
<Content />
</Button>
</UserControl>

Using three different ComboBoxItem styles in one WPF ComboBox

So I'm trying to create a user control for an application I'm working on. It's basically a ToggleButton next to a ComboBox. I was able to pretty much mock the ComboBox portion of the user control up in VS2015 the way the designers want it, but I feel like the way I'm going about it is not exactly the best way.
First, here is a link to a screenshot of what it looks like:
https://www.dropbox.com/s/019f4xqgu8r4i0e/DropDown.png
To do this, I ended up creating 3 different ComboBoxItem styles. The first puts together a CheckBox, a TextBlock with the ContentPresenter, and a Rectangle. The second just has a Separator, and the last just has the TextBlock with the ContentPresenter. Here is my XAML, which is declared in the UserControl.Resources section:
<Style x:Key="cbTestStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border Name="Border"
Padding="5"
Margin="2"
BorderThickness="2"
CornerRadius="0"
BorderBrush="Transparent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="15"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}}"/>
<TextBlock Grid.Column="1"
TextAlignment="Left"
Foreground="Black">
<ContentPresenter/>
</TextBlock>
<Rectangle Grid.Column="2"
Stroke="Black"
Width="15"
Height="15"
Fill="{TemplateBinding Foreground}"/>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="Gray"/>
<Setter TargetName="Border" Property="Background" Value="LightGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="cbSeparatorStyle" TargetType="ComboBoxItem">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Separator/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="cbResetStyle" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="HorizontalAlignment" Value="Stretch"/>
<Setter Property="VerticalAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="Border"
Padding="5"
Margin="2"
BorderThickness="2"
CornerRadius="0"
BorderBrush="Transparent">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="1">
<ContentPresenter/>
</TextBlock>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="Border" Property="BorderBrush" Value="Gray"/>
<Setter TargetName="Border" Property="Background" Value="LightGray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I guess my first question would be, is this the best way to make my ComboBox look like the screenshot I have presented?
Of course, there are deeper issues that I have yet to address. Firstly, the cbTestStyle of ComboBoxItem I want to be able to populate dynamically. Databinding would be my obvious go-to, but with the separator and "Reset" styles at the end, I'm not sure how to do this. I currently have the ComboBoxItems "hard-coded" in XAML:
<ComboBox x:Name="cbTestSelect"
Height="34"
Width="18"
IsEnabled="False">
<ComboBoxItem Style="{StaticResource cbTestStyle}" Content="Test 1" Foreground="#7FFF0000" Selected="ComboBoxItem_Selected"/>
<ComboBoxItem Style="{StaticResource cbTestStyle}" Content="Test 2" Foreground="#7F00FF00" Selected="ComboBoxItem_Selected"/>
<ComboBoxItem Style="{StaticResource cbTestStyle}" Content="Test 3" Foreground="#7F0000FF" Selected="ComboBoxItem_Selected"/>
<ComboBoxItem Style="{StaticResource cbSeparatorStyle}"/>
<ComboBoxItem Style="{StaticResource cbResetStyle}" Content="Reset all"/>
</ComboBox>
In this example, I would ideally like to dynamically create the first three items and have the separator and "reset" items remain static. I'm still relatively new to WPF. I felt like trying to create this control in WinForms (which the application this user control would be used in is) would be a lot more complicated. Plus I'm trying to steer us towards using WPF more anyway.
Any help or links to other questions or tutorials online would be greatly appreciated.
Solution 1:
Use a CompositeCollection so that you can bring up your data items with DataBinding, and use regular XAML to define the hard-coded items:
<Window x:Class="WpfApplication31.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication31"
Title="MainWindow" Height="350" Width="525"
x:Name="view">
<Window.Resources>
<DataTemplate DataType="{x:Type local:DataItem}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Text}"/>
<Rectangle Stroke="Black" StrokeThickness="1"
Fill="{Binding Color}" Width="20"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<ComboBox VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="100" x:Name="Combo">
<ComboBox.Resources>
<CompositeCollection x:Key="ItemsSource">
<CollectionContainer Collection="{Binding DataContext,Source={x:Reference view}}"/>
<Separator Height="10"/>
<Button Content="Clear All"/>
</CompositeCollection>
</ComboBox.Resources>
<ComboBox.ItemsSource>
<StaticResource ResourceKey="ItemsSource"/>
</ComboBox.ItemsSource>
</ComboBox>
</Grid>
</Window>
Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var colors = new[] {"Red", "Green", "Blue", "Brown", "Cyan", "Magenta"};
this.DataContext =
Enumerable.Range(0, 5)
.Select(x => new DataItem
{
Text = "Test" + x.ToString(),
Color = colors[x],
IsChecked = x%2 == 0
});
}
}
Data Item:
public class DataItem
{
public bool IsChecked { get; set; }
public string Text { get; set; }
public string Color { get; set; }
}
Result:
Solution 2:
Using Expression Blend, you can get the XAML for the default Template for the ComboBox control, and modify this XAML to accomodate your extra visuals.
The XAML you get is rather long, and I'm not going to post it here. You will have to put that in a ResourceDictionary and reference that in the XAML where you define this ComboBox.
The relevant part you need to edit is the Popup:
<Popup x:Name="PART_Popup" AllowsTransparency="true" Grid.ColumnSpan="2" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
<Themes:SystemDropShadowChrome x:Name="shadow" Color="Transparent" MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{Binding ActualWidth, ElementName=templateRoot}">
<Border x:Name="dropDownBorder" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" BorderThickness="1" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}">
<DockPanel>
<Button Content="Clear All" DockPanel.Dock="Bottom"/>
<Separator Height="2" DockPanel.Dock="Bottom"/>
<ScrollViewer x:Name="DropDownScrollViewer">
<Grid x:Name="grid" RenderOptions.ClearTypeHint="Enabled">
<Canvas x:Name="canvas" HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
<Rectangle x:Name="opaqueRect" Fill="{Binding Background, ElementName=dropDownBorder}" Height="{Binding ActualHeight, ElementName=dropDownBorder}" Width="{Binding ActualWidth, ElementName=dropDownBorder}"/>
</Canvas>
<ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Grid>
</ScrollViewer>
</DockPanel>
</Border>
</Themes:SystemDropShadowChrome>
</Popup>
Notice that I added a DockPanel, the Button and a Separator.
Then you can bind your ItemsSource to the DataItem collection normally:
<ComboBox ItemsSource="{Binding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="100"/>
Result:
Notice that this approach is a lot better than my previous solution, and other answers posted here, because it does not wrap the extra visuals in ComboBoxItems, and therefore you don't get the selection highlight for them, which is rather weird.
You could use a DataTemplateSelector with the DataTemplates defined in the XAML and some item type variable it the data you're binding to.
public class StyleSelector : DataTemplateSelector
{
public DataTemplate DefaultTemplate
{ get; set; }
public DataTemplate SeparatorTemplate
{ get; set; }
public DataTemplate ResetTemplate
{ get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var type = item as SomeType;
if (type != null)
{
switch (type.SomeItemTypeField)
{
case TypeENum.Separator: return SeparatorTemplate;
case TypeENum.Reset: return ResetTemplate;
default:
return DefaultTemplate;
}
}
return base.SelectTemplate(item, container);
}
}
Check out this more detailed example.
I think your best bet is to learn about DataTemplate and DataTemplateSelector.
Here is an blog post that will show you a simple example of using a DataTemplate.
The ComboBox Control
Essentially, you could bind your ComboBox to a collection of objects, and use a DataTemplateSelector to pick which template to use based on the type of object.

Force my tabitem to calcultate its width

I have the following style for my tabitems :
<Style x:Key="BoutonMenuHaut" TargetType="{x:Type TabItem}">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border Height="40" HorizontalAlignment="Stretch" CornerRadius="0" Name="border">
<Grid>
<ContentPresenterVerticalAlignment="Center"
HorizontalAlignment="Left"
TextBlock.Foreground="{StaticResource CouleurTexteBoutonsHaut}"
TextBlock.FontSize="{DynamicResource FontSizeBig}"
Name="textTab"
ContentSource="Header" Margin="10,0,60,0"
RecognizesAccessKey="True">
</ContentPresenter>
<Rectangle Height="2" x:Name="separation" Fill="Red" VerticalAlignment="Bottom" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
As you can see I bind the fontsize to a value defined like this :
xmlns:sys="clr-namespace:System;assembly=mscorlib"
<sys:Double x:Key="FontSizeBig">16</sys:Double>
And in the window_sizechanged event I do this :
this.Resources["FontSizeBig"] = TextSizeFromResolution(12, height);
where height is the height of the screen.
But when I resize my window my tabitem doesn't resize itself and i'm not able to see all my tabs in the page anymore.
So my question is : How can I force the tabcontrol to resize the tabitems when the size changes ? (because the size of the text has changed so the tabitem's width should change too.
I've tried InvalidateMeasure, Update Layout... but I could not manage to make it work.
Could you help me ?
Thanks !
You could bind the width of the tabs to the ActualWidth of the tab control with a converter:
<Style TargetType="TabItem">
<Setter Property="Width" Value="{Binding
Path=ActualWidth, Converter={StaticResource YourConverter},
RelativeSource={RelativeSource
FindAncestor, AncestorType={x:Type TabControl}}}"/>
</Style>

WPF content control styling

I have a custom control which is basically a contentcontrol
public class PromoAlarmBox : ContentControl
{
static PromoAlarmBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PromoAlarmBox), new FrameworkPropertyMetadata(typeof(PromoAlarmBox)));
}
}
I add it to the containing user control
<controls:PromoAlarmBox Grid.Row="9" Grid.Column="1" />
If I add the style to the containing usercontrols resources everything works fine
<UserControl.Resources>
<Style TargetType="{x:Type controls:PromoAlarmBox}">
<Setter Property="ContentControl.ContentTemplate">
<Setter.Value>
<DataTemplate >
<Rectangle Fill="Blue" Stroke="Black" Height="20" Width="20"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
But if I add it to generic.xaml in the custom controls project , nothing is show
<Style TargetType="{x:Type local:PromoAlarmBox}">
<Setter Property="ContentControl.ContentTemplate">
<Setter.Value>
<DataTemplate >
<Rectangle Fill="Blue" Stroke="Black" Height="20" Width="20"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
I know the style is applied as I have other controls in same project whos styles are defined in generic.xaml, Anyone have any ideas?
A simple static should do the trick...
static PromoAlarmBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PromoAlarmBox), new FrameworkPropertyMetadata(typeof(PromoAlarmBox)));
}
Although im not sure why there is a difference when you use a style as a local resource and when you use generic , this works for me
<Style TargetType="{x:Type local:PromoAlarmBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Rectangle VerticalAlignment="Stretch" Fill="Yellow" Stroke="Black" Height="20" Width="20"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Categories

Resources