How can I apply a custom TextBox style to built-in controls? - c#

Background:
In a standard WPF application, right clicking on a TextBox displays a ContextMenu with three commands: Cut, Copy, and Paste. My desire is to add a Select All command to all TextBox ContextMenus in my application.
Problem:
My standard approach is to create a Style that targets TextBox and supplies the new ContextMenu. That way, all TextBox controls inherit the style and pick up the change.
The trouble is that my style isn't inherited by controls that contain TextBoxes. For instance, when editing a DataGridTextColumn cell, I know a TextBox is used but it doesn't inherit my style. The same goes for some 3rd party controls used by my application.
Question:
Is there some other way to have controls, like the DataGridTextColumn's cell, pick up my style changes, or am I stuck altering their templates?
Addendum:
This is the style:
<Style
TargetType="{x:Type TextBox}"
BasedOn="{StaticResource {x:Type TextBox}}"
>
<Setter
Property="ContextMenu"
>
<Setter.Value>
<ContextMenu>
<MenuItem
Header="Cu_t"
Command="ApplicationCommands.Cut"
InputGestureText="Ctrl+X"
/>
<MenuItem
Header="_Copy"
Command="ApplicationCommands.Copy"
InputGestureText="Ctrl+C"
/>
<MenuItem
Header="_Paste"
Command="ApplicationCommands.Paste"
InputGestureText="Ctrl+V"
/>
<Separator
/>
<MenuItem
Header="Select _All"
Command="ApplicationCommands.SelectAll"
InputGestureText="Ctrl+A"
/>
</ContextMenu>
</Setter.Value>
</Setter>
</Style>

your textbox style will be reflected to textboxes who dont have any style applied. So if you have any third party textbox and it has already a style applied with key. your style will fail. you may need to use expression blend to open the the control template and change style or understand how the textbox style applied there.
cheers..

Related

Setting StringFormat of WPF DatePicker inside UserControl

I have a custom WPF UserControl that uses a DatePicker within it. I'm setting the display format of the DatePicker using the answer provided at this SO article
<Style TargetType="{x:Type DatePickerTextBox}" BasedOn="{StaticResource {x:Type DatePickerTextBox}}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<TextBox x:Name="PART_TextBox"
Text="{Binding Path=SelectedDate, StringFormat='dd-MM-yy', RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I would like to use a different format string for different instances of the control, so I'd like in some way to provide the format when I add the UserControl to the form, something like
<basecontrols:CustomControl
LabelWidth="{StaticResource LabelColumnWidth}"
Label="Custom Information"
DateDisplayFormat="dd-MMMM-yyyy"
/>
Label and LabelWidth are Dependancy properties of the custom UserControl.
Is it possible to have bind the StringFormat to a control property, when it is inside a Binding ? If not, is there a way to do what I want to do?
Hope that makes sense
Is it possible to have bind the StringFormat to a control property, when it is inside a Binding ?
No. You can't bind the StringFormat property of a Binding because it's not a dependency property.
What you could to is to define a DateDisplayFormat dependency property in your CustomControl (which I guess you have done already) and then override the OnApplyTemplate method and create the binding of the TextBox programmatically.
Alternatively, you could use a <MultiBinding> in the XAML markup that binds to both SelectedDate and DateDisplayFormat and use a multi converter that returns a string.

Edit wpf control template but use original styles

Sometimes when I'm editing a copy of the controls original template I don't need to change the original styles and colors, and would like to reference the original ones directly.
For example, I wanted to change the ComboBox template to add some filtering buttons in the drop down, its toggle button refers to a Style that is also copied into the file. I would like to refer to the original style so my XAML isn't overly cluttered.
Edit:
So here is part of the XAML code that is created when you choose to edit a copy.
The ControlTemplate is what I want to change, but I don't need the ComboBoxToggleButton Style, and so for the toggleButton I'd like to set its style to the one the ComboBoxToggleButton Style was copied from. Is there some namespace that they are all stored in, or are they inaccessible?
<Style x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
...
</Style>
<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
...
<ToggleButton x:Name="toggleButton" ... Style="{StaticResource ResourceKey=ComboBoxToggleButton}"/>
</Grid>
</ControlTemplate>
And approximately what I'd like it to be like
<Window xmlns:baseStyles="{namespace/url to the default wpf styles}">
<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
...
<ToggleButton x:Name="toggleButton" ... Style="{StaticResource ResourceKey=baseStyles:ComboBoxToggleButton}"/>
</Grid>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
Right, so Combobox isn't your basic bare templated control. Within it's ControlTemplate is a unique ToggleButton (hence the additional instance-specific Style template for it) which it requires. Once you introduce a new ControlTemplate than that's now all it knows. It CAN NOT reference a Style template inside of the original ControlTemplate since it's not a resource available outside of it. Style and ControlTemplate are different beasts.
You have two options. Either you take that unique ToggleButton Style Template and put it somewhere it can be reached as a StaticResource and ref it on the ToggleButton instance inside your ControlTemplate via the normal <ToggleButton Style="{StaticResource ComboBoxUniqueToggleButtonStyleKeyNameYouGiveIt}" ..../>
(Like if it were in a resource dictionary, except then it's loaded all the time which generally isn't necessary).
Or, you can embed it directly in your ControlTemplate just like they do in the default style/controltemplate for ComboBox.
You can inherit parts of a Style template via BasedOn but you can only have one ControlTemplate at a time.
Hope this helps, and I'll retract my duplicate vote.
To reuse the default WPF style to ComboBox, use:
<Style TargetType="ComboBox">
<!-- Setters in need of change -->
</ Style>
If you want to inherit from a Style you created yourself, you can use:
<Style TargetType="ComboBox" BasedOn="{StaticResource YourExistentStyle}">
<!-- Setters that need to change -->
</ Style>

WPF MenuItem Icon sharing

I want to bind icons to the MenuItem controls where these items are dynamically created. I tried to set the x:Shared attribute to False but always only the last item has icon.
Here is my style for the MenuItems ItemContainerStyle code:
<Window.Resources>
<Style TargetType="{x:Type MenuItem}" x:Key="MenuItemStyle" x:Shared="False">
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding IconSource}" />
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And the MenuItem definition:
<MenuItem Header="Workspaces" ItemsSource="{Binding WorkspaceItems}" Icon="{StaticResource BranchIcon}" ItemContainerStyle="{StaticResource MenuItemStyle}" />
I have already tried to set this Shared attribute on the Image control but no luck.
Any suggestion?
You are almost there!
First of all: don't be confuse by Template vs Style.
When you are setting Icon property to an Image control, only one copy is created. As a control can have only one parent, it is removed from the previous parent each time it's re-assigned.
That's why you see only one icon.
You have 2 solutions for what you want:
use datatemplate instead, and redefine the whole Template of a MenuItem
use a style with a shared image component (what you tried to achieve)
In your example the only error is that the Shared attribute should be false on the Image resource, not on the whole style. This should work:
<Window.Resources>
<Image x:Key="MenuIconImage" x:Shared="false" Source="{Binding IconSource}"/>
<Style TargetType="{x:Type MenuItem}" x:Key="MenuItemStyle" BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Icon" Value="{StaticResource MenuIconImage}">
</Setter>
</Style>
</Window.Resources>
Hope it helps.

WPF Toolbar removing custom styles for controls placed within it

I have defined generic themes (key less, styles based on types), for buttons and text boxes.
When I create a button instance in my Window where these resources are merged, the styles are rendered properly. But for the same button hosted within a ToolBar, the styles are not applied; the style reverts back to Windows default.
Any idea why?
P.S: If I set the style of the buttons hosted within the ToolBar explicitly, then it works fine, but this is something I do not want to do.
This works:
<ToolBarTray>
<ToolBar Band="1"
BandIndex="1">
<Button Content="Add" Style="{DynamicResource ResourceKey={x:Type Button}}" />
</ToolBar>
</ToolBarTray>
This does not work:
<ToolBarTray>
<ToolBar Band="1"
BandIndex="1">
<Button Content="Add" />
</ToolBar>
</ToolBarTray>
In both the cases, if the button is placed outside the ToolBar, styles are applied properly!
So if we go look at a style template for your toolbar we find this in there.
<Style x:Key="{x:Static ToolBar.ButtonStyleKey}"
BasedOn="{StaticResource ToolBarButtonBaseStyle}"
TargetType="{x:Type Button}" />
Which is explicitly defining and overriding your embedded Button's with another style nested in the template.
You can either alter or remove this from the template, or override it at the instance level where you would just change the BasedOn value to point to your own Style template. There's also tutorials out on the net for styling the toolbar for more detailed information. Hope this helps.

How to change the border of a GroupBox based on the ContentControl tag inside it?

I am running into a problem with WPF UI wherein I need to set the border of a GroupBox control based on the fact if there is any checkbox inside the GroupBox that has been unchecked. I have tried writing some code but that didn't work, I am new to WPF and I tried using a style to solve the problem but that didn't work well with me. The code looks as follows -:
<GroupBox Grid.Row="6" Grid.ColumnSpan="3" Header="View Actions" >
<GroupBox.Style>
<Style TargetType="GroupBox" d:DataContext="{d:DesignInstance ActionsViewModels:IActionViewModel}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled}" Value="False">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2"/>
</DataTrigger>
</Style.Triggers>
</Style>
</GroupBox.Style>
<ContentControl Content="{Binding ViewActionsVM}"/>
</GroupBox>
Just FYI, the is used to populate the GroupBox with objects which have a text and checkbox component inside them and look something like this
Now what I want to be able to do is when one unchecks this checkbox I want to be able to add a red border around the Groupbox in which its contained. The content shown in the image comes from the ContentControl binding that we have in our project. To add to the description of the Content, the content describes an Action to be performed and has a property called as IsEnabled that I am using in the DataTrigger to decide whether to add a border or not.

Categories

Resources