WPF DatePicker - autocorrect options - wpf

I have a WPF DatePicker object.
<DatePicker Name="dtp_FilterByDate" />
and
<Application.Resources>
<Style TargetType="{x:Type DatePickerTextBox}">
<Setter Property="Text" Value="Filter by date..." />
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<TextBox x:Name="PART_TextBox"
Text="{Binding Path=SelectedDate, StringFormat = {}{0:yyyy-MM-dd}, FallbackValue='1900-01-01', TargetNullValue='Enter a date...',
RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
When I manually enter a date into the box it automatically corrects it (I understand that it uses Date.Parse then formats it as I specify above), but it's ignoring the fact that my PC's culture is en-GB.
For example, If I enter
07/10/1988
it autocorrects it to
1988-07-10
i.e setting the month to 7 and the day to 10 - which is not expected behaviour for my PC's "en-GB" culture - which expects 1988-10-07 for the yyyy-MM-dd format specified.
If I enter
23/05/2007
The DatePicker shows an error, rather than parsing correctly.
Is there a way to set the culture for the datepicker (or generally for all Date.Parse calls in the application) manually, either to match my PC's or even to specify en-GB in all cases?
Edit - more information
DirectCast(dtp_FilterByDate.Template.FindName("PART_TextBox", dtp_FilterByDate), TextBox)
shows me that the Language is "en-US" - but I don't know why this is the case.

OK, just realised that I can update my style to do this.
Do the following:
<TextBox x:Name="PART_TextBox" Text="{...}" Language="en-GB"/>

Related

Moving a complicated XAML binding to a Style Setter

I'm using a checkbox with a custom style and control template. I would like to move the height and width bindings over to the style as well, but I can't seem to get it right.
Here's the checkbox XAML
<CheckBox Style="{StaticResource MyCheckStyle}"
HorizontalAlignment="Center"
Height="{Binding FontSize,
Source={x:Static gap:Settings.Default},
Converter={StaticResource MyMathConverter},
ConverterParameter='x+10'}"
Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
IsChecked="{Binding ValueT, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
/>
I'm trying to achieve a check box whose height in pixels is 10 larger than the current font size in points (a hack but please ignore that for now).
I'm binding Width to ActualHeight so that they'll always be square (my custom template would allow any size otherwise)
I'm using a converter (Ivan Krivyakov's MathConverter) to do the math.
The size I'm binding to is stored in a static instance of a Settings class generated from a Settings file.
MyCheckStyle is currently as follows:
<Style x:Key="MyCheckStyle" TargetType="{x:Type CheckBox}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template" Value="{StaticResource MyCheckBoxTemplate}" />
</Style>
So far, this all works perfectly. But my attempt at moving the Width Binding to the style crashes the application:
<!-- WIDTH BINDING. CAUSES A CRASH DUE TO ACCESS VIOLATION -->
<Setter Property="Width">
<Setter.Value>
<Binding>
<Binding.Source>
<RelativeSource Mode="Self"/>
</Binding.Source>
<Binding.Path>
<PropertyPath Path="ActualHeight"/>
</Binding.Path>
</Binding>
</Setter.Value>
</Setter>
My attempts at the moving the Height binding are a complete failure. I can't figure out how to replicate the "x:Static" markup extension in element syntax, among other things. Intellisense/ReSharper isn't helping me much.
<Setter Property="Height">
<Setter.Value>
<Binding>
<!-- NO IDEA WHAT TO PUT HERE? -->
</Binding>
</Setter.Value>
</Setter>
</Style>
Anyone able to set me right? Is what I'm doing possible?
Have you ever done
Prop="{Binding Source={RelativeSouce ...}}"?
Nope. It's not Source, it's RelativeSource. The curly brace markup-extension syntax sets the same properties as the XML element syntax, but with curly braces. That's all. If it's RelativeSource with curly braces, it's RelativeSource with angle brackets.
<Setter Property="Width">
<Setter.Value>
<Binding>
<!-- RelativeSource, not Source -->
<Binding.RelativeSource>
<RelativeSource Mode="Self"/>
</Binding.RelativeSource>
<Binding.Path>
<PropertyPath Path="ActualHeight"/>
</Binding.Path>
</Binding>
</Setter.Value>
</Setter>
For x:Static, that's another markup extension (a subclass of System.Windows.Markup.MarkupExtension). If markup extension class names have the Extension postfix, the XAML parser lets you omit the "Extension" part. So as it happens that class is actually named StaticExtension. If you want static member Foo.Bar in the local namespace, easy:
<x:StaticExtension Member="local:Foo.Bar" />
The Binding class is a subclass of MarkupExtension (via BindingBase), which is why you can use the curly-brace syntax with it. However, it doesn't have the "Extension" name postfix. That's optional. There's no particular consistency there.
Key point: Every one of these things is a class. XAML is a notation for instantiating instances of classes and initializing their properties with either scalar values, or with other class instances. Curly-brace markup extension syntax is a funny little addition -- but a useful one, as you can see comparing the XAML above with what I'm about to suggest as a replacement.
Now, that's all well worth knowing, but you don't need any of it here.
tl;dr
<Setter
Property="Width"
Value="{Binding ActualHeight, RelativeSource={RelativeSource Self}}"
/>
<Setter
Property="Height"
Value="{Binding FontSize,
Source={x:Static gap:Settings.Default},
Converter={StaticResource MyMathConverter},
ConverterParameter='x+10'}"
/>
Done.

Why style targettype has to be rebinded back to the original properties?

I am referring to the code block here, on Data triggers
<Window x:Class="WpfTutorialSamples.Styles.StyleDataTriggerSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="StyleDataTriggerSample" Height="200" Width="200">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<CheckBox Name="cbSample" Content="Hello, world?" />
<TextBlock HorizontalAlignment="Center" Margin="0,20,0,0" FontSize="48">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="No" />
<Setter Property="Foreground" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=cbSample, Path=IsChecked}" Value="True">
<Setter Property="Text" Value="Yes!" />
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
</Window>
To me, from programming language design point of view, the line <Style TargetType="TextBlock"> is completely unnecessary, because it is already nested inside the <TextBlock>, so of course whatever setter property should be applied to the TextBlock type. So why need the line <Style TargetType="TextBlock">?
Can <Style TargetType> be of other type except TextBlock?
So why need the line ?
A Style may be defined as a resource, i.e. not inline, and if doesn't have a TargetType specified, how is the XAML parser supposed to be able to parse it and set the properties specified by the setters? It can't. Or at least it doesn't.
Just because you can define a Style inline you are still creating an instance of the exact same class that may be used as a (global) resource and then setting a TargetType is indeed required.
Can be of other type except TextBlock?
No, apart from a type that is derived from TextBlock. If you specify another type you will get an exception at runtime when the BAML (the compiled XAML) is parsed.
You could use any class TextBlock derives from (for example FrameworkElement).
If you implement your own CustomizedTextBlock for example you are able to use styles defined for TextBlock in your project.
You find an example for this here.

focus is wrong when trying to click inside a RadComboBox

So i have a RadCombobBox which is heavilly edited to have a list of options where 1 of the options can be an input field. There are different types of input fields you can chose from but i'm having a problem with the integer input field. There's also one with a text input field which shows no problems.
The combobox looks like this:
The text is dutch (don't mind it) beneath the text options there is a preset value, the idea here is you can either choose a preset setting (which corresponds to an integer value) or you can type in your own value.
What happens when i try to click on different places (last one is very peculiar):
If i try to click on the input box (which is highlighted in gray) it selects it and closes the combo box (this is not what i want).
If i try to click on the arrows on the right side of the combobox it changes the value.
If i scroll with my mouse, it changes the value.
If i keep my mouse down on the input box i can actually type in the value i want.
If i first click on the buttons on the side and then click inside the input box i can edit the value.
What I want is to click on the input box and be able to edit the value inside and when i'm finished press enter (or outside the combobox) to close it.
Somehow the focus or, something (i am not 100% sure) just seems to fail me.
here is the xaml code for the IntegerDataTemplate:
Integer selector
<Style x:Key="NumericUpDownStyle" TargetType="{x:Type telerik:RadNumericUpDown}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
</Trigger>
<Trigger Property="IsEditable" Value="False">
<Setter Property="SmallChange" Value="0" />
<Setter Property="LargeChange" Value="0" />
</Trigger>
</Style.Triggers>
</Style>
<!-- Integer editor -->
<DataTemplate x:Key="IntegerDataTemplate">
<telerik:RadNumericUpDown x:Name="NumericUpDown"
Width="{Binding Path=ActualWidth,
ElementName=Editor}"
MaxWidth="{Binding Path=ActualWidth,
ElementName=Editor,
Converter={StaticResource WidthToWidthConverter}}"
HorizontalContentAlignment="Left"
Background="Transparent"
FontFamily="{telerik:Windows8Resource ResourceKey=FontFamilyStrong}"
IsInteger="True"
Style="{StaticResource NumericUpDownStyle}"
UpdateValueEvent="PropertyChanged"
Value="{Binding Path=Value,
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True}">
<telerik:RadNumericUpDown.NumberFormatInfo>
<globalization:NumberFormatInfo NumberGroupSeparator="" />
</telerik:RadNumericUpDown.NumberFormatInfo>
</telerik:RadNumericUpDown>
</DataTemplate>
<!-- Integer as Option -->
<DataTemplate x:Key="OptionsDataTemplate">
<TextBlock Height="20" Text="{Binding Converter={StaticResource IntegerSelectorObjectToStringConverter}}" />
</DataTemplate>
<local:SelectorTypeTemplateSelector x:Key="IntegerTemplateSelector"
OptionsDataTemplate="{StaticResource OptionsDataTemplate}"
SelectorDataTemplate="{StaticResource IntegerDataTemplate}" />
Somewhere it is going wrong, is there anyone that can point me to the right way to fix it (a work around would be fine as well).
I would like to add I have the same code but with a text box which does work properly, I've added the code below to have a comparison but i haven't been able to find a significant difference.
Text selector (which actually works properly)
<Style x:Key="TextBoxStyle" TargetType="{x:Type telerik:RadWatermarkTextBox}">
<Setter Property="BorderBrush" Value="{StaticResource BasicBrush}" />
<Setter Property="FontFamily" Value="{telerik:Windows8Resource ResourceKey=FontFamilyStrong}" />
<Setter Property="Padding" Value="2,2,0,0" />
<Setter Property="Validation.ErrorTemplate" Value="{StaticResource ErrorTemplate}" />
<Setter Property="telerik:RadWatermarkTextBox.WatermarkTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Margin="2,3,0,0"
FontFamily="Segoe UI"
FontStyle="Italic"
Foreground="{StaticResource WaterMarkBrushNoOpacity}"
Padding="0,-2,0,0"
Text="{Binding}" />
</DataTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="BorderBrush" Value="{StaticResource AccentBrush}" />
</Trigger>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource MarkerDisabledBrush}" />
</Trigger>
</Style.Triggers>
</Style>
<!-- String editor -->
<DataTemplate x:Key="StringDataTemplate">
<telerik:RadWatermarkTextBox x:Name="WatermarkTextBox"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Top"
Background="Transparent"
BorderThickness="1"
Style="{StaticResource TextBoxStyle}"
Text="{Binding Path=Value,
UpdateSourceTrigger=PropertyChanged,
NotifyOnSourceUpdated=True}" />
</DataTemplate>
<!-- String as Option -->
<DataTemplate x:Key="OptionsDataTemplate">
<TextBlock Height="20" Text="{Binding Converter={StaticResource StringSelectorObjectToStringConverter}}" />
</DataTemplate>
<local:SelectorTypeTemplateSelector x:Key="StringTemplateSelector"
OptionsDataTemplate="{StaticResource OptionsDataTemplate}"
SelectorDataTemplate="{StaticResource StringDataTemplate}" />
It's really difficult to know what's going on without actually fiddling around with all the bits and pieces (e.g. the RadComboBox style + code), but it would be natural to assume that is has something to do with the drop down automatically closing when it loses focus, especially given that the standard WPF ComboBox has a FocusedDropDown state which opens the popup.
You could try and duplicate the RadComboBox by importing the style from Telerik, and extending the code behind into a new class (and restyle with the imported template). This way you can override methods and attach to events (e.g. Got/LostFocus), and play around with the template to see if you can adjust it to your needs.
However trying to wrestle such behavior into existing controls, just because it is possible to restyle the templates, often just ends up in a lot of grief (and hours wasted).
I have a feeling it would be easier to create a NumericRadComboBox which has the numeric up/down embedded in the combobox itself. So you restyle the RadComboBox to have numeric up/down buttons next to the drop down arrow, and implement the increment/decrement behavior manually.
The solution was rather simple, I was trying to fix it with preview mouse down but what i needed to do was on preview mouse up by adding: PreviewMouseLeftButtonUp="EditorPreviewMouseLeftButtonUp" in the xaml, which made the RadComboBox code as follows:
telerik:RadComboBox x:Name="Editor"
BorderThickness="0"
FontWeight="SemiBold"
ItemTemplateSelector="{StaticResource IntegerTemplateSelector}"
PreviewMouseLeftButtonUp="EditorPreviewMouseLeftButtonUp"
SelectionBoxTemplate="{StaticResource SelectionboxTemplate}"
Validation.ErrorTemplate="{StaticResource ErrorTemplate}" />
The code behind looked lik this:
private void EditorPreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var originalSource = e.OriginalSource as FrameworkElement;
if ((originalSource != null) && (originalSource.ParentOfType<TextBox>() != null))
{
e.Handled = true;
}
}
The MouseUp is when the selection changed event is called which causes the combobox to close, by stating the event is finished before that happens it won't close the combobox. All you now have to do is press enter after you've changed the value and it will be selected and updated correctly.

How to apply different content to a single property in style located in Resource Dictionary?

I have 2 textboxes which using AddItemTextBoxStyle:
<TextBox x:Name="txtItemA" Style="{StaticResource AddItemTextBoxStyle}"></TextBox>
<TextBox x:Name="txtItemB" Style="{StaticResource AddItemTextBoxStyle}"></TextBox>
Inside the AddItemTextBoxStyle (which is a style in Resource Dictionary), I have a tag property which sets the watermark text within the textbox:
<Style x:Key="AddItemTextBoxStyle" TargetType="{x:Type TextBox}" BasedOn="{StaticResource CustomTextBoxStyle}">
<Setter Property="Tag" Value="Type here" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<TextBlock Style="{StaticResource WaterMarkTextStyle}" x:Name="WaterMarkLabel" Text="{TemplateBinding Tag}" />
</ControlTemplate>
</Setter.Value>
</Setter.Property>
</Style>
By default, the watermark text is "Type here". However, if I want the watermark text to be different in the two textboxes, for example:
Textbox txtItemA - "Type Item A here"
Textbox txtItemB - "Type Item B here"
May I know how can I do this? Since the style is located in resource dictionary.
I try to search online but still unable to find a clue for it.
<TextBox x:Name="txtItemA" Style="{StaticResource AddItemTextBoxStyle}" Tag="Some wathermark" />
<TextBox x:Name="txtItemB" Style="{StaticResource AddItemTextBoxStyle}" Tag="Another watermarks" />
notice, that your style just sets default value of tag. Actual value is set in control instance and template binding takes the value from instance, not from style.

WPF DataGrid Hyperlink Appearance and Behaviour

I am quite new to WPF, there is so much to learn and I think I'm getting there, slowly. I have a DataGrid which is used for display and user input, it's quite a tricky Grid as it is the main focus of the entire application. I have some columns that are read-only and I have used a CellStyle Setter to set KeyboardNavigation.IsTabStop to False to keep user input focused on the important columns and that works fine. I would like a couple of the read-only columns to be hyperlinks that show a tooltip and do not receive the focus, however I am struggling to write the XAML that will achieve all three requirements at the same time.
One of the columns is to indicate if the item on the row has any Notes. I have used the following XAML to display a HasNotes property in the cell in a DataGridTemplateColumn and on the Tooltip show the actual notes, in the Notes property:
<DataGridTemplateColumn x:Name="NotesColumn" Header="Notes">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding HasNotes, Mode=OneWay}">
<TextBlock.ToolTip>
<TextBlock Text="{Binding Notes}" MaxWidth="300" TextWrapping="Wrap" />
</TextBlock.ToolTip>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
That works fine but I would like to make it a Hyperlink instead so the user can do something with the Notes when they click on the cell contents.
I have another column which is a DataGridHyperlinkColumn used to display a Unit of Measurement on a hyperlink and when clicked the user can change the unit. (The reason I have done it like this, rather than a ComboBox for example, is because as much as I want the user to be able to change the unit I want to make the interface such that it is a very deliberate act to change the unit, not something that can be done accidentally). The following XAML puts the Hyperlink column on for Unit
<DataGridHyperlinkColumn x:Name="ResultUnitLink" Binding="{Binding Path=Unit.Code}" Header="Unit" Width="Auto" IsReadOnly="True">
<DataGridHyperlinkColumn.CellStyle>
<Style>
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridHyperlinkColumn.CellStyle>
<DataGridHyperlinkColumn.ElementStyle>
<Style>
<EventSetter Event="Hyperlink.Click" Handler="ChangeUnit" />
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
One problem with the XAML for the Hyperlink column is that the IsTabStop = False doesn't appear to work, when tabbing through the Grid my hyperlink column still receives the focus, unlike the other columns where I've used a setter to change IsTabStop. If push comes to shove I could live with that but I'd rather not.
What I actually want from both those columns is an amalgamation of the two appearances/behaviours i.e. Columns where the data is displayed on a hyperlink, where TabStop = False and which display a tooltip of a different property when hovered over.
Can anyone help advise me how to get a column that achieves the following:
Hyperlink displaying one property
Tooltip displaying a different property
IsTabStop = False that actually works when used with a hyperlink
Thanks in advance to anyone who can help.
I've had issues with the Hyperlink in the past, so have this Style which I use for Labels or Buttons to make them look like Hyperlinks. Try making your column Template into a Button or a Label and applying this style.
<Style x:Key="ButtonAsLinkStyle" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter ContentStringFormat="{TemplateBinding ContentStringFormat}" />
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>

Resources