Using Large Font and Buttons for WPF calendar - wpf

I need to provide large fonts for date numbers, month, Day-of-week headers and prev/next buttons for a WPF calendar. This is a touch-screen application with no mouse.
What is the ABSOLUTE SIMPLEST MINIMAL xaml code to do JUST this? I don't want pretty or clever. I just want BIG FONTS. Big enough for mechanics to locate and press on a grubby, dusty, grease-coated screen.
One thing I've tried is below. That didn't work. I don't understand it and don't want to. I don't have time to go chasing down all this template styling mishmash. Honestly what I'm after is for someone to just cook something up and give it to me. I'm running out of time, and I just want this thing in my rearview.
Style TargetType="{x:Type Calendar}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Calendar}">
<CalendarItem x:Name="PART_CalendarItem"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"/>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="PART_CalendarItem" Property="Padding" Value="0,0,0,0" />
<Setter TargetName="PART_CalendarItem" Property="Background" Value="Yellow" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

I don't see you changing the FontSize in the XAML you provided but no matter. I just tried it and it looks like the default template ignores it anyway. Probably the best approach then would be to redefine the Template but I agree, that could be a lot of initial work. I sympathize too... I have been where you are too and been just as frustrated (i.e. try making the scrollbar wider/taller than the default size, ugh!)
So, if all you need is to just make the control larger then a simple approach would be to add a Scale to the LayoutTransform. For example, to double the size try:
<Style TargetType="{x:Type Calendar}">
<Setter Property="LayoutTransform">
<Setter.Value>
<TransformGroup>
<ScaleTransform ScaleX="2" ScaleY="2"/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Setter.Value>
</Setter>
</Style>

Related

How to set specific control element settings that override a global style in WPF?

I have defined a global style for Buttons in my application via an application-wide Resource Dictionary. The style looks like this (followed from another SO Example):
<Style TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{DynamicResource BaseButtonBG}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!-- Triggers here -->>
</Style.Triggers>
It works. But I need to assign specific values directly to some of my buttons, like margin and padding to align them. I also would like to have the ability to override the color properties from the style in individual buttons.
It appears that any properties I set directly on specific buttons get completely ignored and only the properties from the global style are used. How do I overcome this?
UPDATE: To clarify what I want:
In the HTML/CSS world (which is older than dirt), you can add a style class to an element, but you can also assign properties directly to the element that override the class values. That's what I want to accomplish in WPF.
UPDATE 2
It's possible people think this question is stupid because the solution should be obvious. However, from my personal testing, there appears to be a bug with Padding not changing at all unless you specifically bind it in a control template. This behavior seems to change from property to property. Since my original attempt to override a property specifically involved Padding and it didn't work, I had to build this workaround.
Ok, form in Design:
XAML code for form:
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Foreground" Value="Red"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Button Content="Button" x:Name="btnNo1" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="120"/>
<Button Content="Button" x:Name="btnNo2" HorizontalAlignment="Left" Margin="135,10,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
and in RunTime we going to change Margin by using this code in CS file:
public MainWindow()
{
InitializeComponent();
btnNo2.Margin = new Thickness(100, 100, 100, 100);
}
Result will be:
Can you create and use new style for button where you need custom margin/padding?
<Style x:Key="SpecialButtonType1" BasedOn="{StaticResource ResourceKey=CommonButtonStyle}">
...
</Style>
and change
<Style TargetType="Button">
to
<Style TargetType="Button" x:Key="CommonButtonStyle">
YES: It's completely doable, You can assign overriding properties directly on an element without doing the ugly process many are using of creating a special one-off dictionary entry just for the specific element in question.
I don't know if its caused by a bug in WPF, but there's an initial requirement...
Your dictionary-referenced base style might need to include any properties that you want to be overridable. For some reason different properties seem to exhibit different behavior. But at least in the case of Padding, if you don't include Padding on your ControlTemplate TemplateBinding, you won't be able to override it on your element.
Additionally, in the case of margin, there seems to be some kind of "doubling" effect that happens if you include Margin in the ControlTemplate TemplateBinding. If you don't templateblind the margin, you can still override margin but the behavior changes.
STEP 1
Define a base style with a ControlTemplate. Make sure that your ControlTemplate includes a TemplateBinding for all properties that you may want to customize/override on individual elements.
<Style TargetType="Button">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="{StaticResource BaseButtonBG}"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}"
Margin="{TemplateBinding Margin}"
>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource BaseButtonBG_IsMouseOver}"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Background" Value="{StaticResource BaseButtonBG_IsPressed}"/>
</Trigger>
</Style.Triggers>
</Style>
I've defined a few StaticResource keys for my property colors so that I can put them altogether in another place for cleaner skinning. Here are those keys:
<SolidColorBrush x:Key="BaseButtonBG" Color="#5f636c"/>
<SolidColorBrush x:Key="BaseButtonBG_IsMouseOver" Color="#898C94"/>
<SolidColorBrush x:Key="BaseButtonBG_IsPressed" Color="#484B51"/>
STEP 2
Implement actual button like this:
<Button Content="New" />
And the result of this makes a button that looks like this:
STEP 3
Now let's say I want all of my buttons to look squashed like that, except one. I want to add some vertical padding to make one specific button look taller. I could alter the example button like this:
<Button Content="New" Padding="0,30"/>
And the result:
Alternatively, you could implement the button override as follows, which gives you the ability to override Triggers or other special Style options.
<Button Content="New">
<Button.Style >
<Style TargetType="Button" BasedOn="{DynamicResource {x:Type Button}}">
<Setter Property="Padding" Value="0,30"/>
</Style>
</Button.Style>
</Button>
TADA! We've assigned a one-off style tweak directly to the element WHERE IT BELONGS! We didn't have to create a style in a dictionary and reference it for this one case.
Important Points
In order to make this work "Padding" MUST BE defined in the ControlTemplate with the TemplateBinding code. If you don't do that, Padding directly applied to the button just gets ignored completely. Again, I'm not sure why its like this, but that seems to be the magic fix.
Further Reading: I was able to figure this out from some helpful info on this blog article:
explicit-implicit-and-default-styles-in-wpf
Interestingly, the last part of that article suggests creating a custom control with your own default style and properties that you can override similarly to how I've done here. This seems a bit overkill to me, but it might eliminate the weird bugginess problem with padding and margin behaving differently. Haven't tried that yet, though.

How can I add a simple shape-indicator to the end of the progress line on a ProgressBar?

Lately I've had to re-style my WPF application based off of a style guide given to me by a designer. One of my new requirements is to change the look of the ProgressBar.
Most of the changes are rather simple, however what I'm having a difficult time figuring out is how can I add a simple shape to the end of the progress line.
I'm not trying to draw a shape at the far-right edge of the progress bar. Instead, If the progress meter is at 50%, I'd like to draw a Circle at the 50% point, and so on. Below is a sample image of what I'm trying to accomplish.
Please note, I've done something similar for the Slider control. However, it appears to be a much different beast. Thanks for the guidance.
Something like this works for me
<Style TargetType="{x:Type ProgressBar}">
<Setter Property="BorderBrush" Value="#235b92" />
<Setter Property="Foreground" Value="#235b92" />
<Setter Property="BorderThickness" Value="2" />
<Setter Property="Background" Value="#e8f0f7" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ProgressBar}">
<Grid Background="{TemplateBinding Background}"
Margin="10,5">
<Border x:Name="PART_Track"
BorderThickness="2"
BorderBrush="{TemplateBinding BorderBrush}" />
<Border x:Name="PART_Indicator"
HorizontalAlignment="Left"
Background="{TemplateBinding Foreground}">
<Ellipse Fill="#06e5ed" HorizontalAlignment="Right" VerticalAlignment="Center" Width="20" Height="20" Margin="-10,-5"/>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
That code yields the following result for me:
Whereas the red dotted area is just the highlighted PART_Indicator control

Binding to last Validation Error

I have a style trigger for create a tooltip with a validation error:
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel>
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="2" Background="{x:Null}">
<AdornedElementPlaceholder/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
I'm displaying first error (Validation.Errors)[0].ErrorContent), but I want to display the last one (the last is more prioritary, Framework textbox adds its validation errors at the end, for example strings not representing a date).
Thanks.
Well, for one thing you could change the Path to all errors and add a ValueConverter that returns only the last message.
A lot of people also move validation completely to the view-model and ditch the validation rules, that way you have a lot of control over what exactly you expose to the view.

WPF Control Focus with Touch Screen Monitor and Windows 10

I am developing an application using WPF and VB.net in Visual Studio 2013. This application is to run on a computer with a touch screen monitor.
My development PC is running windows 7, but the computer that will be running this application is using Windows 10. I don't know if this is a specific issue to Windows 10 or a touch interface.
The issue I am having is when using the touch screen monitor, a control is highlighted after you touch the control. I cannot figure out how to automatically remove this highlight. I have tried to change focus and/or set focusable property to false. The only way to stop the control from being highlighted is to touch somewhere else on the screen.
But in Windows 7 using a mouse, I can change focus and with the focusable property set to false; the control does not receive focus at all.
This program is being used without a keyboard(physical or virtual) or mouse. Having a control highlighted is undesirable, in my opinion.
Any advice on how to remove the highlight or prevent it altogether would be greatly appreciated.
All the buttons are highlitghed while the cursor is on them, if you want you can disable the hightlight but it will be disable always. To do so create a custom style and give it to your button, i give you an example:
<Window.Resources>
<Style x:Key="CloseButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Margin" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border"
BorderThickness="1"
Padding="4,2"
BorderBrush="Transparent"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="Red" />
<Setter TargetName="border" Property="BorderBrush" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
this piece of code remove the highlight of your button and change is background to red when you enter it with your cursor. To add it to your button do like this:
<Button x:Name="CloseButton" Style="{StaticResource CloseButtonStyle}" />
Hope it helps :)

Image Button only responds when clicking on the image and not the area around inside the button

I'm using the following button style which takes away the borders and makes a transparent background to make my image buttons:
<Style x:Key="EmptyButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="#00000000"/>
<Setter Property="BorderBrush" Value="#00000000"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
Margin="{TemplateBinding Padding}"
RecognizesAccessKey="True"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The Style is from the following answer:
WPF button with image of a circle
The problem now is that the clickable area is confined to the image regardless of how big the actual button is:
My button code:
<Button Name="n02" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Style="{DynamicResource EmptyButtonStyle}" Canvas.Left="308" Canvas.Top="157" Height="106" Width="120">
<Image Source="boto_face_off.PNG" Height="61" Width="59" />
</Button>
Question: how do I make the whole button area react to the click? I want to keep it transparent and without border as it is now.
You could wrap the presenter in a Border with a bound Background.
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<!-- ContentPresenter here -->
</Border>
</ControlTemplate>
The style sets the Background to something transparent but it was never even used in the Template, this way the Border will make the whole area hit-test.
Just adding some info to the answer above after investigating the issue for hours.
If you are defining your own template as in the example above you are changing the visual tree of the element. In the above example applying the Style="{DynamicResource EmptyButtonStyle}" it becomes:
Button
|
ContentPresenter
But if you look at the visual tree of a standard button(you can do this in Visual Studio) it looks like this:
Button
|
ButtonChrome
|
ContentPresenter
So in the styled button there is nothing around the ContentPresenter to be clicked on, and if the Content is in the "middle" the surrounding area will be left totally empty. We have to add an element to take this place:
You can do it with a <Border>(I think this is best because Border is a lightweight element I suppose) or some other element, I tried <Grid> and <DockPanel> and both worked.
The only thing I don't understand is why you need to explicitly set the background to something transparent, just leaving it out will not produce a clickable area.
Edit: Last point answered in the comments here Image Button only responds when clicking on the image and not the area around inside the button
I have Button where content is Grid containing Image and TextBlock
I fixed clickable area by adding Transparent Background to grid
Background="#00000000"

Resources