WPF: TextTrimming on a ContentPresenter - c#

Is there a simple way to just get TextTrimming to work with a ContentPresenter?
I have implict styles for TextBlock and AccessText that have TextTrimming set to CharacterEllipsis, but it's not picked up by the ContentPresenter. I can change the ContentPresenter to an AccessText or TextBlock and set it there, but then the template only handles text content.
Any suggestions?
Thanks!

Implicit Styles for elements that derive from UIElement, but not Control, are not applied if the element is defined in a control's Template unless the implict Style is defined in the application Resources. The same holds true for TextBlocks used by ContentPresenter.
For example, in the following XAML the TextBlock that is ultimately used to present the button's content will not get the implicit Style:
<Window.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Window.Resources>
<StackPanel>
<Button Content="Will not be red" />
<TextBlock Text="Will be red" />
</StackPanel>
If you take that exact same Style and move it to the application's Resources, then both will be red:
<Application.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Application.Resources>
So you can either move your implicit Style to application resources, which is generally not a good idea. Or you can customize the display for the specific scenario you have. This can include adding an implicit DataTemplate, or customizing a control's Template.
If you can provide more information, then it would be easier to know which is the best approach.

Thanks to this Gist by James Nugent: "WPF style which puts character ellipsis on button contents without replacing the ContentPresenter with a TextBlock and thus losing the ability to support access keys."
This worked for me:
<ContentPresenter.Resources>
<Style TargetType="TextBlock">
<Setter Property="TextTrimming" Value="CharacterEllipsis"></Setter>
</Style>
</ContentPresenter.Resources>

Related

How to apply a setting in a style that will not be overwriiten by a lower-level style

I have a fairly complicated app, and I have a simple Attached Behavior I want to set on all of my TextBoxes.
The attached behavior works fine, when I set it directly on the element:
<TextBox
Text="{KtWpf:OrdinaryBinding Path=contact}"
utilityClasses:TextBoxBehavior.SelectAllTextOnFocus="True"
/>
And it works fine when I set it via an unnamed style in a resource of an element that contains the TextBox:
<Grid>
<Grid.Resources>
<Style TargetType="TextBox">
<Setter
Property="utilityClasses:TextBoxBehavior.SelectAllTextOnFocus"
Value="True" />
</Style>
</Grid.Resources>
[...]
But if I apply it via an unnamed style in a higher-level resource, it does not apply to elements that have an unnamed style in a lower-level resource:
<KtWpf:KorUserControl>
<KtWpf:KorUserControl.Resources>
<Style TargetType="TextBox">
<Setter
Property="utilityClasses:TextBoxBehavior.SelectAllTextOnFocus"
Value="True" />
</Style>
<Grid>
<Grid.Resources>
<Style TargetType="TextBox">
<Setter Property="Width" Value="200" />
</Style>
</Grid.Resources>
[...]
<TextBox
Text="{KtWpf:OrdinaryBinding Path=contact}"
/>
I'd expect one of two behaviors, either:
WPF would search out all of the unnamed styles with TargetType="TextBox", starting at the outermost, applying each setting in turn, perhaps overwriting settings from the outer styles with settings from the inner styles, or
WPF would search outwards from the TextBox element until it found the innermost style that would apply, and use that, ignoring all others.
From what I've found in my testing, WPF is doing the second. In this case, what I want is the first.
How do I define a setting in a style that applies globally, even if there are unnamed styles on the TargetType that are defined at lower levels?
I think you can't do that. Lower level generic styles will always override upper level generic styles. I don't think there are "multiple styles" elements.
But, you can name the higher level style (make it non-generic), and use BasedOn="{StaticResource baseStyle}" in the lower level generic style.
Just my opinion obv.

WPF using style that contains another style

I'm trying to make a progress bar style that is re-usable.
So the idea here is very simple. I have a style already with target type ProgressBar, and it's just a spinny circle that fills as it goes from 0-100%. However, in order to make it re-usable and modular, I do not want to hard-code the text that goes along with it - it should be optional.
So I want to create another style that DOES include text "Downloading... X/Y MB". For this I take Value for X, Maximum for Y, and Tag for the unit. I want to include the same spinny circle thingy for the graphical part on the left. How can I do this? With BasedOn property, I think you can only set something already there to be different. What if I want to add additional elements (like textblocks in this case)?
If only text value differentiates then within style you can bind propertie's value to parent's property like Tag where at every single either style or element you adjust it to specific requirement.
<Window.Resources>
<Style x:Key="FirstButtonStyle" TargetType="Button">
<Setter Property="Content" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SecondButtonStyle" TargetType="Button" BasedOn="{StaticResource FirstButtonStyle}">
<Setter Property="Content" Value="2"/>
</Style>
</Window.Resources>
<StackPanel>
<Button Style="{StaticResource FirstButtonStyle}"/>
<Button Style="{StaticResource SecondButtonStyle}"/>
</StackPanel>
The outcome is 1 and 2. If your intent is to inject some UI element within style then there is no such an option, alas. Style needs to be rewritten once again.

WPF ControlTemplate - default style

I want to use the default style of buttons and just want to add a Grid and Stackpanel with 2-3 Bindings. When i add the ControlTemplate in my Style all Trigger-, Border-, ...settings are overwritten. How can i just add my Grid/Stackpanel/Bindings while using the rest of the default settings?
<Style x:Key="listbutton">
<Setter Property="Button.Height" Value="40"/>
<Setter Property="Button.Margin" Value="0,3"/>
<Setter Property="Button.Template">
<Setter.Value>
<ControlTemplate>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The purpose of a ControlTemplate is to define how a Control must be displayed. You can't have a ControlTemplate based on another ControlTemplate (it wouldn't make sense). What you can do is take the default ControlTemplate and modify it at your will.
The default ControlTemplate for Button can be found here

Bind column header visibility without losing global style

I want to bind the column header visibility of a wpf listview to a dependency property without losing the global style (expression dark) I used.
I defined a style:
<Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="Visibility" Value="{Binding ColumnHeaderVisibility}" />
</Style>
Then I applied it like this:
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
I'm using the expression dark theme. It's imported via MergedDictionaries and can be changed in runtime.
Everything is fine when the column header is invisible. But when visible it is shown in default windows style, because setting the ColumnHeaderContainerStyle overrides the expression dark style.
Using "BasedOn" on the original style is no option, because all resources are dynamic due to the requirement to change style in runtime. BasedOn only works on static resources, which won't allow changing in runtime.
What else can I do?
Not sure if this will work but you can try to base style on the default style.
<Style x:Key="myHeaderStyle" TargetType="{x:Type GridViewColumnHeader}" BasedOn="{StaticResource {x:Type GridViewColumnHeader}}">
<Setter Property="Visibility" Value="{Binding ColumnHeaderVisibility}" />
</Style>

Setting a style on Control type not working

I'm writing a very basic WPF dialog and want to apply a simple style to all objects that inherit from the Control class. The code I'm using:
<Window.Resources>
<Style TargetType="{x:Type Control}">
<Setter Property="Margin" Value="20"/>
</Style>
</Window.Resources>
<StackPanel>
<TextBlock Text="some text"/>
<TextBox x:Name="x_NameTextBox"/>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button x:Name="x_CancelButton" Click="x_CancelButton_Click" Content="Cancel"/>
<Button x:Name="x_OkButton" Click="x_OkButton_Click" Content="OK"/>
</StackPanel>
</StackPanel>
</Window>
The Style defined above doesn't change the layout of the window at all unless I specify a key and set the style on each individual object, which is exactly what I'm trying to avoid. It also works for more specific types (setting the TargetType to Button, for example.)
Any ideas why this isn't working?
Every control when it gets instantiated it gets its Style from the explicitly defined resource or look for the immediate parent where it can get a default style. In your case the Button control will get its default Style from the platform because your App haven't defined one. Now that platform Button Style has no way to know about your custom defined Control base style. Because styles will look for a base style only when you explicitly define BasedOn
So you got only two ways
1. Define Style for every control - which you don't want I think.
2. Define Styles for the controls you are interested and set the BasedOn
<Style TargetType="{x:Type Control}">
<Setter Property="Margin" Value="20"/>
</Style>
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource {x:Type Control}}">
</Style>

Categories