In an application I'm working on, we have a bunch of custom controls with their ControlTemplates defined in Generic.xaml.
For instance, our custom textbox would look similar to this:
<Style TargetType="{x:Type controls:FieldTextBox}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type controls:FieldTextBox}">
<Border BorderThickness="0" Margin="5">
<StackPanel ToolTip="{Binding Path=Field.HintText, RelativeSource={RelativeSource TemplatedParent}}">
<TextBlock Text="{Binding Path=Field.FieldLabel, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Left"
/>
<TextBox Width="{Binding Path=Field.DisplayWidth, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Left"
Text="{Binding Path=Field.Data.CurrentValue, RelativeSource={RelativeSource TemplatedParent}}"
IsEnabled="{Binding Path=Field.IsEnabled, RelativeSource={RelativeSource TemplatedParent}}"
ContextMenu="{Binding Source={StaticResource FieldContextMenu}}" >
<TextBox.Background>
<SolidColorBrush Color="{Binding Path=Field.CurrentBackgroundColor, RelativeSource={RelativeSource TemplatedParent}}"/>
</TextBox.Background>
</TextBox>
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Focusable" Value="True" />
<Setter Property="IsTabStop" Value="False" />
</Style>
In our application, we need to be able to programatically set the focus on a particular control within the ControlTemplate.
Within our C# code, we can get to the particular "FieldTextBox" based on our data. Once we have the correct FieldTextBox, we need to be able to set the focus on the actual TextBox contained within the ControlTemplate.
The best solution I've come up with is to set a name on the primary control in each control template (in this case it's the TextBox), such as "FocusableControl."
My code (contained in the code-behind for the FieldTextBox) to then set focus on the control would be:
Control control = (Control)this.Template.FindName("FocusableControl", this);
if (control != null)
{
control.Focus();
}
This solution works. However, does anyone else know of a solution that would be more efficient than this?
Within your control template you can add a Trigger that sets the FocusedElement of the StackPanel's FocusManager to the textbox you want focused. You set the Trigger's property to {TemplateBinding IsFocused} so it fires when the containing control is focused.
You can get rid of the hard coding of control name in the code by providing some DependancyProperty and have the same code in controlLoaded or OnApplyTemplate function based on the DependancyProperty.
This DependancyProperty's sender will the candidate for .Focus() call.
Related
So im trying to make button appear on right click in my ListBox.
<ListBox Grid.Column="1" Margin="358,44,20,63" Name="scriptbox" Background="#FF282828" Foreground="White" SelectionChanged="Scriptbox_SelectionChanged" BorderThickness="0">
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem
Template="{DynamicResource MenuItemTemplate}"
Header="Delete"
Click="MenuItemDelete_Click" >
</MenuItem>
</ContextMenu>
</ListBox.ContextMenu>
This is my MenuItem template.
<ControlTemplate TargetType="{x:Type MenuItem}" x:Key="MenuItemTemplate">
<Border x:Name="Border" Background="#FF282828" Padding="30,5,30,5" BorderThickness="0" Margin="0">
<ContentPresenter ContentSource="Header" x:Name="HeaderHost" RecognizesAccessKey="True" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter Property="Background" TargetName="Border" Value="#51544e"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<ItemsPanelTemplate x:Key="MenuItemPanelTemplate">
<StackPanel Margin="-3,0,0,0" Background="White"/>
</ItemsPanelTemplate>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="ItemsPanel" Value="{StaticResource MenuItemPanelTemplate}"/>
</Style>
Everything is fine but there is white border all around the button.
What you recognize as a white border is the ContextMenu itself that contains your MenuItems. Try adding more buttons and changing the Background and BorderBrush of the ContextMenu and you will see.
<ContextMenu Background="Red" BorderBrush="Blue">
Changing the brushes like this will lead to this result, which makes it obvious.
If you create a custom control template for your MenuItems you should probably do so for the ContextMenu, too, if only setting brushes does not fit your requirements. As you can see in the example, there is still a vertical white line that is part of the default control template, that you might want to get rid of. You can start from this example, although it is neither the default template nor complete. Look at this related post for guidance on how to extract the default control template for ContextMenu if you need it.
How can replace default checkbox style with png image, for checked state and unchecked state.
Here is and what I try but is not complilated with xaml:
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<CheckBox.Background>
<Image Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" Width="16" Height="16" />
</CheckBox.Background>
</CheckBox>
I try and this code but then image go in content is not replaced.
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<Image Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" Width="16" Height="16" />
</CheckBox>
Is possible to replace default style?
In this particular case, you will need to fiddle with the Template of the CheckBox.
<CheckBox IsChecked="{Binding AirTemperatureGridChecked}">
<CheckBox.Template>
<ControlTemplate TargetType="{x:Type CheckBox}">
<Grid>
<Image x:Name="Foo" Width="16" Height="16" Source="https://cdn4.iconfinder.com/data/icons/cc_mono_icon_set/blacks/48x48/checkbox_unchecked.png" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="False">
<Setter TargetName="Foo" Property="Opacity" Value="0.5" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</CheckBox.Template>
I've made this one from scratch to just give an example of how quick and easy it is to get your own templates up and running for the design of controls.
As you can see, it's made of a grid, with your image inside, and below that is a trigger that will make the checkbox lower its opacity when unchecked.
You can put just about anything in that grid to design your checkbox as you would any window, and give it functionality with triggers.
Additionally (as giving each and every checkbox this mass of code would be unreasonable) you can give the controltemplate a key:
<ControlTemplate x:Key="WhateverYouWantToCallMe" TargetType="{x:Type CheckBox}">
<!-- Content ect... -->
</ControlTemplate>
Put it inside a Resource Dictionary and call it as a StaticResource for the checkbox instead, like so:
<CheckBox Template="{StaticResource WhateverYouWantToCallMe}"/>
I have a dialog in my WPF application which contains a ListBox. The ListBox uses the following DataTemplate to display its contents:
<DataTemplate x:Key="AlarmClassTemplate">
<CheckBox Content="{Binding Path=Value}"
IsChecked="{Binding IsChecked}" />
</DataTemplate>
I've also configured the following template and style to display when there is an error in the ListBox's contents:
<ControlTemplate x:Key="InputErrorTemplateA">
<DockPanel LastChildFill="True">
<Image DockPanel.Dock="Right"
Height="30"
Margin="5"
Source="{StaticResource ErrorImage}"
ToolTip="Contains invalid data"
VerticalAlignment="Center"
Width="30" />
<Border BorderBrush="Red"
BorderThickness="5"
Margin="5">
<AdornedElementPlaceholder />
</Border>
</DockPanel>
</ControlTemplate>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource InputErrorTemplateA}" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<Binding Path="(Validation.Errors).CurrentItem.ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
And here's the XAML for the ListBox itself:
<ListBox FontSize="20"
FontWeight="Bold"
Grid.Column="1"
Grid.ColumnSpan="2"
Grid.Row="1"
Height="158"
ItemsSource="{Binding Path=IDs, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
ItemTemplate="{StaticResource AlarmClassTemplate}"
Margin="5,0,110,0"
Name="AlarmClassListBox"
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
Visibility="{Binding Converter={StaticResource BoolToVisibility}, Path=DataTypeIsAlarms}" />
The validation logic for the data in the ListBox is that at least one item has to be checked off. If none of them are, the ListBox should display an error and the OK button on the dialog should be disabled.
The good news is that the OK button on the dialog is indeed disabled when nothing in the ListBox is checked. The bad news is that the Style doesn't seem to be working, in that no red border is displayed around the ListBox and the error image (a red circle with a white exclamation point inside) does not show.
I'm using the same exact ControlTempate and a similar Style on other controls on the same dialog and they work fine. What am I doing wrong? Is it the ListBox? Does ListBox validation work differently?
Indeed the problem is you weren't raising PropertyChanged event for your validation to gets fired.
But i can see one more issue in your code. You have set local value for tooltip on ListBox here:
ToolTip="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"
But you want different tooltip in case validation returns some error which you define in style triggers.
But, local value has higher precedence order than style triggers. So, your tooltip will never be set. So, you should move the tooltip to style setters to work:
<Setter Property="ToolTip"
Value="{x:Static res:Car.EditDataRetention_AlarmClasses_ToolTip}"/>
MSDN link - Dependency property value precedence.
I found the answer to my problem in this post. It turns out that I have to raise the PropertyChanged event when the checkboxes change in order for the Validation logic to fire. Since the items in the ListBox implement INotifyPropertyChanged, it was easy to add an event listener for each item as it's added to the ListBox which raises the necessary event.
Thanks anyway.
i got a DataTemplate for a listboxitem and i want to create a triger , so when a user click an item the background will change and also the label
my code:
<Window.Resources>
<Style x:Key="RoundedItem" TargetType="ListBoxItem">
<EventSetter Event="MouseDoubleClick" Handler="listViewItem_MouseDoubleClick" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="ItemBorder" CornerRadius="10" BorderBrush="Black" BorderThickness="1" Margin="1" Background="Transparent">
<Label Name="ItemLabel" Foreground="Red" >
<ContentPresenter />
</Label>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="DeepSkyBlue" />
<Setter TargetName="ItemLabel" Property="Foreground" Value="Orange" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<DataTemplate x:Key="TitleTemplate" DataType="models:Title" >
<StackPanel>
<Image Source="{Binding ThumbFilePath}" Width="50" HorizontalAlignment="Center"/>
<Label Content="{Binding Name}" HorizontalAlignment="Center" />
<TextBlock Text="{Binding Description}" HorizontalAlignment="Center" TextWrapping="Wrap" Padding="5,5,5,5"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
What happend is that the TextBlock change his color and not the label..
anyone know why ?
Thanks.
The TextBlock inherits the Foreground definition from its parents in the visual tree. The Label, on the other hand, defines the Foreground in its default style.
Your approach is "non-WPF-like" - you shouldn't wrap the ContentPresenter in a Label control.
The right approach depends on whether you want all text in the item to change its Foreground, or just the label?
[In both cases, there's no apparent benefit to using a Label in the data template - so I'll assume that the label is changed to TextBlock.]
If the answer to the above question is that all text should be changed: in the ControlTemplate of the ListBoxItem, in the trigger for IsSelected, from the seccond setter remove TargetName="ItemLabel" so the final setter is:
<Setter Property="Foreground" Value="Orange" />
This will change the foreground of the item that will affect the foreground of both TextBlocks in the data template.
If you want to affect just one of the TextBlocks:
1. remove the setter for the foreground from the control template
2. add a trigger to your data template:
<DataTemplate>
<StackPanel>
<Image .../>
<TextBlock x:Name="Text01" ..../>
<TextBlock x:Name="Text02" ..../>
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter TargetName="Text01" Property="Foreground" Value="Orange"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
Side note: if you have to use Label control in your data template, bind its Foreground property to the Foreground of the list box item, like so:
<Label Foreground="{Binding Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"....../>
If this doesn't help, it means that your list box item inherits its foreground, so use:
<Label Foreground="{Binding TextElement.Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"....../>
I want to tack on to this that I was experiencing a similar problem where I'd added a ListBox.ItemTemplate to my ListBox, and the styling then did not apply to the text anymore.
What I was doing was trying to display a list of languages (CultureInfo) for the user to select from, however I wanted the native names to display, not the English name. For some reason, not all languages have their native names capitalized in their CultureInfo, and NativeName is the only instance of their name, so I needed to apply a function to the CultureInfo.NativeName to capitalize the names myself. To accomplish this, I added the ItemTemplate with a Data Template inside, on which I applied a converter.
<ListBox IsSynchronizedWithCurrentItem="True" VerticalAlignment="Center" MinHeight="200" x:Name="cbLanguages"
ItemsSource="{Binding Path=SupportedCultures, Mode=OneWay, Source={StaticResource CultureResourcesDS}}"
FontSize="24" HorizontalAlignment="Stretch" Width="300" Margin="10"
Style="{DynamicResource ListBoxTemplate}" ItemContainerStyle="{DynamicResource ListBoxItemStyle}">
<ListBox.ItemTemplate>
<DataTemplate>
<Label Content="{Binding Converter={StaticResource NativeNameConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
After a while of searching, I came across XAMeLi's answer here, and changed the Label I'd put in the DataTemplate to a TextBox, and the ListBoxItemStyle I'd created worked again.
Basically, Labels and TextBoxes have different traits that can be exploited, or can cause annoying issues in this case. Here's a good explanation with some examples of the differences: http://joshsmithonwpf.wordpress.com/2007/07/04/differences-between-label-and-textblock/
I want to be able to "change" my listview into another control. I was thinking having the control's visibility set to hidden and when a button is clicked, change the visibility. Do I have to do this programatically? Or can I use a trigger?
You can use a trigger to change the Template property of a ContentControl, which will wrap the control you want to be "changeable". Check this:
Add this to Resources:
<ControlTemplate x:Key="BoxTemplate">
<TextBox Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ContentControl}},Path=Content}" />
</ControlTemplate>
<ControlTemplate x:Key="BlockTemplate" >
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ContentControl}},Path=Content}" />
</ControlTemplate>
<ControlTemplate x:Key="TestTemplate" >
<StackPanel>
<CheckBox x:Name="Switch" />
<ContentControl x:Name="MyContent" Template="{StaticResource BoxTemplate}"
Content="Data is unique!" />
</StackPanel>
<ControlTemplate.Triggers>
<Trigger SourceName="Switch" Property="IsChecked" Value="True">
<Setter TargetName="MyContent"
Property="Template"
Value="{StaticResource BlockTemplate}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Test it using another ContentControl:
<ContentControl Template="{StaticResource TestTemplate}"/>
I'm sure it could be optimized, but should put you on the track.
You can use a Storyboard and/or trigger to do this, no problem. Just animate the Visibility properties on the elements you want to change.
To add to Muad'Dib's answer, another way you can do it is to stack the controls on top of each other, then fade the Opacity back and forth in the trigger. You can also do this with VSM (Create a ListboxVisible state and a ListboxHidden state, or whatever name makes more sense semantically)