I rewrite a ComboBoxItem by custom control with these code:
XAML:
<Style TargetType="{x:Type local:SComboBoxItem}">
<Setter Property="Padding" Value="5,15"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:SComboBoxItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" Cursor="{TemplateBinding Cursor}" >
<Label Foreground="{TemplateBinding Foreground}" Margin="{TemplateBinding Padding}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontWeight="{TemplateBinding FontWeight}" Padding="0" Content="{TemplateBinding Content}">
</Label>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#dbdbdb"></Setter>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="#c9c8c9"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Code-behind:
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.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SealBase
{
public class SComboBoxItem : ComboBoxItem
{
static SComboBoxItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SComboBoxItem), new FrameworkPropertyMetadata(typeof(SComboBoxItem)));
}
}
}
Well, and then I make a demo as this:
<ComboBox Grid.Column="1" Margin="10,10,0,10" HorizontalContentAlignment="Stretch" Name="FontFaimlyCB" Height="50" Width="250">
<Seal:SComboBoxItem>123</Seal:SComboBoxItem>
<Seal:SComboBoxItem>123</Seal:SComboBoxItem>
<Seal:SComboBoxItem>123</Seal:SComboBoxItem>
<Seal:SComboBoxItem>123</Seal:SComboBoxItem>
</ComboBox>
All is OK as below:
However, after I change the code of the demo as this:
<ComboBox Grid.Column="1" Margin="10,10,0,10" HorizontalContentAlignment="Stretch" Name="FontFaimlyCB" Height="50" Width="250" ItemsSource="{Binding Source={x:Static Fonts.SystemFontFamilies}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Seal:SListBoxItem Content="{Binding}">
</Seal:SListBoxItem>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
And now it turns out to be something wrong:
The demo occurs a strange blue blank. I don't know why it turns out to be this. I doubt it is the problem of the ComboBox control. But after I rewrite a brand new one inherits the ComboBox with the custom control. The problem still here.
What's wrong with this? And how can I solve it? Thank you.
What's wrong with this?
The element in the ItemTemplate automatically gets wrapped in a ComboBoxItem container.
And how can I solve it?
If you want to render a SListBoxItem for each item, you could create a custom ComboBox class that overrides the GetContainerForItemOverride() method:
public class CustomComboBox : ComboBox
{
protected override bool IsItemItsOwnContainerOverride(object item)
{
return (item is SListBoxItem);
}
protected override DependencyObject GetContainerForItemOverride()
{
return new SListBoxItem();
}
}
Related
I'm styling TabItems of a TabControl. The problem is, the style affects items of nested TabControls. Propagating styles are the only way I know to get to the TabItems. Anyone know how to style the TabItems on just the outer TabControl?
In my case, the inner tabs are defined in plugins, so I can't access them to try this answer.
Demo app
Here's a demo app of my situation.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TabControl ItemsSource="{Binding}">
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" Background="Red">
<ContentPresenter ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding TabName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<ContentControl Content="{Binding TabConent}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public class TabData
{
public string TabName { get; set; }
public Label TabConent
{
get
{
// In real case, this TabControl from someone else's plugin
var content = new TabControl();
content.Items.Add(new TabItem() { Header = "Nested Tab Item" });
return new Label() { Content = content };
}
}
}
public MainWindow()
{
DataContext = new ObservableCollection<TabData>() { new TabData() { TabName = "Tab Item" } }; ;
InitializeComponent();
}
}
}
Use this, and tell if this is what you want :
<TabControl.Resources>
<Style TargetType="TabItem">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=TabControl, AncestorLevel=2}}" Value="{x:Null}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Border Name="Border" Background="Red">
<ContentPresenter ContentSource="Header"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</TabControl.Resources>
I'm binding a button command, in a ControlTemplate, to an Execute() method in a CustomControl. I'm using a RoutedCommand, the CanExecute() fires, but the Execute() never does. When the CustomControl is placed in the main window, the code works as expected. When it is placed in a Usercontrol, I have this issue. I have tried several ways to wire up the buttons Command (RelayCommand etc) but can't seem to figure out what's wrong. Any help is appreciated.
For context, this is a TokenizingTextBox control - an early fork of the Xceed open source version. The button is for deleting the token from the list of tokens.
The complete style of a TokenIten (which contains the button of interest):
<Style TargetType="{x:Type local:TokenItem}">
<Setter Property="Background" Value="#F3F7FD" />
<Setter Property="BorderBrush" Value="#BBD8FB" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Cursor" Value="Arrow" />
<Setter Property="Padding" Value="2,1,1,1" />
<Setter Property="Margin" Value="1,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TokenItem}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
CornerRadius="0,0,5,5"
Margin="{TemplateBinding Margin}"
>
<StackPanel Orientation="Horizontal" Margin="1" x:Name="myRoot">
<ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" />
<Button Margin="3,0,0,0" Cursor="Hand"
Command="{x:Static local:TokenizedTextBoxCommands.Delete}" CommandParameter="{TemplateBinding TokenKey}"
PresentationTraceSources.TraceLevel="High">
<!--<Button.Template>
<ControlTemplate TargetType="Button">
<ContentPresenter />
</ControlTemplate>
</Button.Template>-->
<Image Source="/Resources/delete8.png" Width="8" Height="8" />
</Button>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The static Command:
public static class TokenizedTextBoxCommands
{
private static RoutedCommand _deleteCommand = new RoutedCommand();
public static RoutedCommand Delete => _deleteCommand;
}
The Custom Control inherits from ItemsControl. In the non-static constructor, we wire up the static delete command to the DeleteToken method:
public TokenizedTextBox()
{
CommandBindings.Add(new CommandBinding(TokenizedTextBoxCommands.Delete, DeleteToken, CanDelete));
}
Finally CanDelete which just sets CanExecute to true:
private void CanDelete(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
{
canExecuteRoutedEventArgs.CanExecute = true;
}
And DeleteToken - functionality omitted, signature is really only important thing here:
private void DeleteToken(object sender, ExecutedRoutedEventArgs e)
{
...
}
So, hopefully this is enough information for anyone interested in providing guidance/suggestions. Thanks.
Little interest here so I hired a Mentor through Pluralsight. The bindings were correct, but the CustomControl had a RichTextBox which was capturing the Mouse Click. We fixed the issue using a Behavior targeting the Button's PreviewMouseDown.
I try to create a ControlTemplate for my Label like this :
<Style TargetType="{x:Type Label}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle Height="30" HorizontalAlignment="Left" Margin="10"
Stroke="transparent"
VerticalAlignment="Top" Width="3"
Fill="#FF259FED" />
<ContentPresenter HorizontalAlignment="Left" Margin="17,0,0,0" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#7A7E81" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
I want to fill color of rectangle when i create my control, like this for example :
<Label Content="Prénom" VerticalAlignment="Top" CouleurRectangle="#FF259FED" />
So, how can I change Property "Fill" in my controlTemplate to set dynamicly color of rectangle when i create control ?
thank's a lot.
Edit : this is the solution , i create a new class who inherit from Label like this :
Public Class LblTitreChamp
Inherits Label
Public Shared ReadOnly CouleurProperty As DependencyProperty =
DependencyProperty.Register("CouleurRectangle", GetType(SolidColorBrush), GetType(LblTitreChamp))
''' <summary>Propriété pour insérer une couleur au début du Label</summary>
Public Property CouleurRectangle As SolidColorBrush
Get
Return GetValue(CouleurProperty)
End Get
Set(ByVal value As SolidColorBrush)
SetValue(CouleurProperty, value)
End Set
End Property
End Class
then, in my COntrolTemplate :
<Style TargetType="{x:Type local:LblTitreChamp}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:LblTitreChamp}">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle Height="30" HorizontalAlignment="Left" Margin="10"
Stroke="transparent"
VerticalAlignment="Top" Width="3"
Fill="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Label}}, Path=CouleurRectangle}"/>
<ContentPresenter HorizontalAlignment="Left" Margin="17,0,0,0" RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#7A7E81" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
and finally, to creat a new label :
<my:LblTitreChamp Content="ID" VerticalAlignment="Top" CouleurRectangle="Black" />
thank's a lot for you :)
hi set Fill={TemplateBinding CouleurRectangle} .Hope this will help. And i Expect that you have created a custom Label class That inherit from Label and has DependencyProperty CouleurRectangle.
Since your label is not a CustomControl, then you cannot dynamically make a property on that so the best possible way is to use the background property of label
...
<Rectangle Height="30" ...
Fill="{TemplateBinding Background}" />
...
Else create a CustomControl inheriting the Label and make a new dependency property and also define a XAML template style for it.
The text is grayed out when the DatePicker is disabled and I want the content to be easier to read.
What I did on some TextBoxes was:
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
It did make the text easier to read.
I do manage to change the Foreground colour on the DataPicker but it does not do the trick. The text was still grayed out.
Seems like there is another property I need to set to make the content of the disabled DatePicker easier to read.
So, how do I make the content of my disabled DatePicker easier to read?
Can you extend DatePicker by adding bool DependencyProperty called Editable.
I found a working example at the following link, note that I run this code in .NET 4.
Here is the DatePicker Control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
namespace DatePickerStyle
{
public class ExtendedDatePicker : DatePicker
{
public static readonly DependencyProperty EditableProperty = DependencyProperty.Register("Editable", typeof(bool),
typeof(ExtendedDatePicker), new PropertyMetadata(true));
public bool Editable
{
get { return (bool)GetValue(EditableProperty); }
set { SetValue(EditableProperty, value); }
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var textBox = GetTemplateChild("PART_TextBox") as DatePickerTextBox;
var binding = new Binding { Source = this, Path = new PropertyPath(ExtendedDatePicker.EditableProperty) };
textBox.SetBinding(UIElement.FocusableProperty, binding);
}
}
}
Here is the XAML:
<Window x:Class="DatePickerStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:DatePickerStyle="clr-namespace:DatePickerStyle"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<DatePicker IsEnabled="True" Grid.Row="0" SelectedDate="2002/12/31"/>
<DatePicker IsEnabled="False" Grid.Row="1" SelectedDate="2002/12/31"/>
<DatePickerStyle:ExtendedDatePicker Editable="True" Grid.Row="2" SelectedDate="2002/12/31"/>
<DatePickerStyle:ExtendedDatePicker Editable="False" Grid.Row="3" SelectedDate="2002/12/31"/>
</Grid>
</Window>
My I suggest this simpler, universal approach?
<ControlTemplate x:Key="MyDisabledDatePicker">
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock
Text="{Binding Path=SelectedDate, StringFormat={}{0:d}, RelativeSource={RelativeSource TemplatedParent}}"
VerticalAlignment="Center" HorizontalAlignment="Left" Padding="10,0,0,0"/>
</Border>
</ControlTemplate>
<Style TargetType="{x:Type DatePicker}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="false">
<Setter Property="Template" Value="{StaticResource MyDisabledDatePicker}" />
</DataTrigger>
</Style.Triggers>
</Style>
Presto!
the above code w ExtendedDatePicker works, first I thought it didn't but that was because the dropdown could still change the text and the Editable="False" doesn't work on the dropdown
so don't forget to add the following to the ExtendedDatePicker
Editable="False" AllowDrop="False" IsDropDownOpen="False" IsHitTestVisible="False" IsManipulationEnabled="False"
I am planning on writing a hierarchical organizational control, similar to an org chart. Several org chart implementations are out there, but not quite fit what I have in mind.
Binding fields in a DataTemplate to a custom object does not seem to work.
I started with a generic, custom control, i.e.
public class NodeBodyBlock : ContentControl
{
public NodeBodyBlock()
{
this.DefaultStyleKey = typeof(NodeBodyBlock);
}
}
It has a simple style in generic.xaml:
<Style TargetType="org:NodeBodyBlock">
<Setter Property="Width" Value="200" />
<Setter Property="Height" Value="100" />
<Setter Property="Background" Value="Lavender" />
<Setter Property="FontSize" Value="11" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="org:NodeBodyBlock">
<Border Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"
Background="{TemplateBinding Background}" CornerRadius="4" BorderBrush="Black" BorderThickness="1" >
<Grid>
<VisualStateManager/> ... clipped for brevity
</VisualStateManager.VisualStateGroups>
<ContentPresenter Content="{TemplateBinding Content}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My plan now is to be able to use this common definition as a base definition of sorts, with customized version of it used to display different types of content.
A simple example would be to use this on a user control with the following style:
<Style TargetType="org:NodeBodyBlock" x:Key="TOCNode2">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=NodeTitle}"/>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
and an instance defined as
<org:NodeBodyBlock Style="{StaticResource TOCNode2}" x:Name="stTest"
DataContext="{StaticResource DummyData}" />
The DummyData is defined as
<toc:Node NodeNumber="mynum" NodeStatus="A"
NodeTitle="INLine Node Title!"
x:Key="DummyData"/>
With a simple C# class behind it, where each of the fields is a public property.
When running the app, the Dummy Data values simply do not show up in the GUI. A trivial test such as
<TextBlock Text="{Binding NodeTitle}" DataContext="{StaticResource DummyData}"/>
works just fine.
Any ideas around where I am missing the plot?
Update: Binding to the datacontext in the definition in generic.xaml works fine, but any binding in the ContentPresenter is lost.
Your control template is missing a binding on the ContentPresenter, it should look like this:-
<ContentPresenter Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
I just ended up using this example as a base:
http://10rem.net/blog/2010/02/05/creating-customized-usercontrols-deriving-from-contentcontrol-in-wpf-4
Not quite sure what I missed, but the example works.