Bind column header visibility without losing global style - c#

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>

Related

Style BasedOn a style defined in ControlTemplate Resources

I'm using a 3rd party ContentControl which comes with the following theme:
<Style TargetType="{x:Type xyz:XyzControl}" x:Key="XyzControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type xyz:XyzControl}">
<ControlTemplate.Resources>
<Style TargetType="Button">
<!-- A lot of styling... -->
</Style>
</ControlTemplate.Resources>
<!-- More template stuff... -->
I want to add some DataTriggers to buttons inside this control but I want to keep the default styling from the control theme.
<xyz:XyzControl>
<Button>
<Button.Style>
<Style TargetType="Button" BasedOn="{???}">
<Style.Triggers>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</xyz:XyzControl>
I tried to base on {StaticResource {x:Type Button}} but this loads the default global button style, not the default style in this context.
This is not possible since you can't base a ControlTemplate on another ControlTemplate. You will have to re-define the entire template as a whole:
WPF: Is there a way to override part of a ControlTemplate without redefining the whole style?
And adding a trigger to a Style won't affect or "override" the triggers that are defined in the ControlTemplate of the control so you will have to override the entire ControlTemplate from scratch.
You could of course copy the default one into your XAML markup and edit it as per your requirements.
Add a key to the 3rd party's button style :
<Style TargetType="Button" x:key="xyzbuttonStyle">
then :
<Style TargetType="Button" BasedOn="{StaticResource xyzbuttonStyle}">

Trying to apply multiple styles to a DataGridRow

I have WPF application, i created DataGrid style in App.xaml to apply whole application.
App.xaml
<Style TargetType="DataGrid" x:Key="GridStyle1">
<Setter Property="HorizontalGridLinesBrush" Value="LightGray" />
<Setter Property="VerticalGridLinesBrush" Value="LightGray" />
<Setter Property="AlternatingRowBackground" Value="WhiteSmoke" />
<Setter Property="RowHeight" Value="30" />
<Setter Property="RowStyle">
<Setter.Value>
<Style TargetType="DataGridRow">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Cyan" />
</Trigger>
</Style.Triggers>
</Style>
</Setter.Value>
</Setter>
</Style>
Then in window :
window1.xaml
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
The problem that window style does not apply ( font style not italic )
It looks like you want to apply a global style to every DataGridRow in every DataGrid in multiple windows, and you also want to apply additional styling to DataGridRow in one or more DataGrids in one particular window.
If you've learned CSS before, you may expect stylesheets to be cumulative: In CSS, if you apply tr.style1 globally and tr.style2 locally, you get both, with tr.style2 winning the toss in any cases where they set the same attribute.
That's not how styles work in XAML. In XAML, an element may inherit styling from its parent, but it can have at most one Style of its own. Additionally, as you've found, Style has a BasedOn property. You can base one style on another, and get the cumulative effects of both.
Lastly, there are several ways to apply a style. You've found that you can apply them to every element of a given type in a given scope.
Unfortunately, because everything depends on context, the way XAML styles are applied can be very confusing at first (and at second, and sometimes third). Particularly when you are using one style (GridStyle1) to apply another style. It's not always obvious what overrides what.
It's best to keep things as simple as possible. We'll get rid of that RowStyle setter, because we don't need it. We'll just create a global DataGridRow Style that applies by default to every DataGridRow everywhere, and then we'll override that specifically in window1.xaml.
App.xaml
<Application.Resources>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="Background" Value="Cyan" />
</Style>
</Application.Resources>
window1.xaml
<Window.Resources>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
</Window.Resources>
That will apply to every DataGridRow in that window. The BasedOn attribute there will refer to whatever style has already been defined for DataGridRow in any containing context -- commonly, that means App.xaml, and if we don't add anything else, that'll be the case here.
The difference between this and what you had is that you were applying the Cyan Background style in a different way: The DataGridRow style you applied in App.xaml was applied via the RowStyle setter on your DataGrid style. That style was BasedOn WPF's pre-existing default Style for DataGridRow, and then it was forcibly applied to every DataGridRow in every DataGrid that used the GridStyle1 style.
The DataGridRow style you defined in window1.xaml would have applied, if DataGrid.RowStyle hadn't already been set in GridStyle1.
But as we've seen, you don't need to use RowStyle to apply a style globally to every DataGridRow. You can do that with the default style for that type, as in my App.xaml fragment above. DataGrid.RowStyle is useful for individually overriding the global DataGridRow style on one particular DataGrid. But you don't want to do that globally! So your styles in App.xaml should look like this:
App.xaml
<Style TargetType="DataGrid" x:Key="GridStyle1">
<Setter Property="HorizontalGridLinesBrush" Value="LightGray" />
<Setter Property="VerticalGridLinesBrush" Value="LightGray" />
<Setter Property="AlternatingRowBackground" Value="WhiteSmoke" />
<Setter Property="RowHeight" Value="30" />
</Style>
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="Background" Value="Cyan" />
</Style>
And again, here's the Style in window1.xaml
<Style TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
Extra Credit
The styles above should solve your problem.
But there are other ways to approach this stuff. Unless you're very comfortable with what we did above, what follows may just add confusion, so if you start reading this and you find that the more you read, the less you understand -- then stop reading! It can wait!
You could also make all text in a DataGrid be italic, but that changes the headers too so I don't think it's what you want:
<DataGrid
FontStyle="Italic"
/>
If you want to apply that Italic style on just one grid in window1.xaml, here's how to do that. If we add an x:Key attribute to a Style, it won't be applied to every DataGridRow in scope. Instead, it's just sitting there, waiting to be used by name as a StaticResource.
window1.xaml
<Window.Resources>
<Style x:Key="ItalicDataGridRowStyle"
TargetType="DataGridRow" BasedOn="{StaticResource {x:Type DataGridRow}}">
<Setter Property="FontStyle" Value="Italic" />
</Style>
</Window.Resources>
<-- ... -->
<!-- One grid with italic rows -->
<DataGrid
x:Name="dataGrid1"
RowStyle="{StaticResource ItalicDataGridRowStyle}"
/>
<!-- And another grid with default rows -->
<DataGrid
x:Name="dataGrid2"
/>
And here's another way to apply styling to the rows in just one grid in window1.xaml:
<!-- Yet another grid -->
<DataGrid
x:Name="dataGrid3"
>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow" BasedOn="{StaticResource ItalicDataGridRowStyle}">
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="Wheat" />
</Style>
</DataGrid.RowStyle>
</DataGrid>
Finally, you could have set RowStyle in GridStyle1, and then explicitly set RowStyle on specific grids in specific windows, as above. That would work. You could have also created a new DataGrid style in window1.xaml (based on GridStyle1) which set RowStyle to something else.

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

WPF: TextTrimming on a ContentPresenter

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>

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