Question about Data Template or Style in WPF xaml - wpf

I have a textbox that has the following simple XAML (not necessary to read it - just have it for reference):
<TextBox Name="m_ctrlUserDeviceType" Style="{StaticResource textStyleTextBox}" Text="{Binding Source={x:Static api:MySettings.Instance}, Path=UserDeviceType, ValidatesOnExceptions=true, NotifyOnValidationError=true}" Validation.Error="TextBox_Error" MinHeight="25" Margin="4" VerticalAlignment="Top" MaxLength="23" VerticalContentAlignment="Center" HorizontalAlignment="Left" MinWidth="100"></TextBox>
For completeness, the style textStyleTextBox looks like this (again, not necessary to read to answer question):
<Style x:Key="textStyleTextBox" TargetType="TextBox">
<Setter Property="Foreground" Value="#333333" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="MinHeight" Value="2" />
<Setter Property="MinWidth" Value="100" />
<Setter Property="Margin" Value="4" />
<Setter Property="MaxLength" Value="23" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalAlignment" Value="Left" />
<!-- <Setter Property="Binding Source" Value="{x:Static api:MySettings.Instance}"/>
<Setter Property="Binding ValidatesOnExceptions" Value="true" />
<Setter Property="Binding NotifyOnValidationError" Value="true" /> -->
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
I have a lot of the stuff (MiHeight, Margin, etc.)in the style because I have a lot of these textboxes and they're almost exactly the same. In fact, there's a lot more in common than just the style. The details of the binding to the class MySettings are almost the same. The only difference is which particular property the textbox is binding too. Additionally, I always user TextBox_Error for Validation.Error.
Is there a way to put the binding info in Style or Data Template so I don't have to keep typing it for each textbox?
I would need to be able to assign an individual property (Path) for each textbox, and I suppose I still need the ability to not use any of it for some particular textbox added in the future (that has nothing to do with databinding to MySettings).
Is there a way to put the TextBox_Error part inside of style or DataTemplate? Using Setter Property did not seem to work for me.
I keep mentioning Data Template as I think the answer might have something to do with that based on reading Pro Silverlight 2 in C# 2008. However, I wasn't able to figure it out. I also tried adding stuff to "Style" as you can see from the commented out stuff in that section.
Thanks,
Dave

I dont think that there is a way to do what you are asking. However, I do think that you could go about it a different way.
What I would look into, is creating a custom control that extends TextBox, then create some dependency properties that, when the control is initialised, setup the bindings and error validation.
This way you can use your custom textbox all over your app and control every property, and even style them the same (just change the target type of your style)
HTH

Related

Styling Telerik WPF NumericUpDown Control

I use Telerik WPF controls and need to add a NumericUpDown control to my UI. The thing is when used "as it is" it doesn't fit the rest of the application visually
<TL;DR>
This is a bigger application, that's not been written fully by me. Other people somehow managed to "import" other telerik controls and assign them other styles. Sadly, nobody's used the UpDown control before.
</>
I added the control to my UI:
<telerik:RadNumericUpDown
Minimum="0"
Maximum="10"
SmallChange="1"
NumberDecimalDigits="0"
IsInteger="True"
Value="{Binding Path=Counter}" />
Also, I've added some styling to a ResourceDictionary:
<Style TargetType="{x:Type telerikInput:RadNumericUpDown}">
<Setter Property="Padding" Value="1"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="Border.CornerRadius" Value="2" />
<Setter Property="Border.Background" Value="{StaticResource ControlBackgroundBrush}" />
<Setter Property="Border.BorderBrush" Value="{StaticResource SolidBorderBrush}" />
<Setter Property="Border.BorderThickness" Value="1" />
</Style>
And this handles some basic styling features (border, margin, etc). In general it looks "good enough". There's only one problem - when a mouse pointer hovers over the control, it becomes shiny and glossy. That's not like my other controls behave - is there an easy way to remove this effect ?
I've tried experimenting with Triggers:
<Style>
...
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="Border.BorderBrush" Value="Black" />
...
</Style.Triggers>
</Style>
But this didn't do much. I've also tried setting IncreaseButtonContentTemplate field, but this turned out no good either.
You need to modify the default ControlTemplates and remove any "shiny and glossy" effects from them. The easiest way to do this would be to copy the default templates from the Themes.Implicit folder in your Telerik installation directory into your solution and then edit them as per your requirements.
There is no "DisableEffects" property that you can simply set on the control I am afraid.

How to make a styled DataGridCheckBoxColumn to respect DataGrid.IsReadonly?

I have DataGrid.IsReadonly bound to a property that changes based on a condition. The DataGrid contains a DataGridCheckBox column that I had to style in order to center it vertically in a cell.
However, after applying a style the check box column does not respect the parent's IsReadonly value. That is, regardless of its value the checkbox can be clicked on and changed. I've seen quite a number of posts dealing with somewhat similar situations but could not find a reliable solution.
Could someone please let me know how to style the checkbox column so it respects its parent griddata's IsReadonly? Any theory behind it would also be appreciated.
This how I apply the style:
<Style x:Key="CenterStyleCB" TargetType="{x:Type CheckBox}">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
<DataGridCheckBoxColumn ... ElementStyle="{StaticResource CenterStyleCB}" />
Add the following code into your style:
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Column.IsReadOnly, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridCell}}}" Value="True">
<Setter Property="IsHitTestVisible" Value="False" />
</DataTrigger>
</Style.Triggers>
If your DataGrid is always ReadOnly, then I would suggest you skip the trigger and use the setter directly.

How to modify legacy named style for having different setters based on targetTypes?

I have this named style
<Style x:Key="validationSupport" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="5,2,14,2" />
...OMISSIS...
<Style.Triggers>
...OMISSIS...
<DataTrigger Binding="{Binding DataContext.ActiveWorkspace.Editable, RelativeSource={RelativeSource AncestorType=Window}}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
I use it extensively for TextBoxes, ComboBoxes, DatePickers etc, so I used as TargetType a super class for all these elements, Control.
Now I would like to differentiate the setter inside the dataTrigger using specific properties that 'Control' doesn't have. It seems I have to create different styles with different names,each for every targetType I want to differentiate, but that way I have to change the style name inside all elements which use it. Is there a smarter way to achieve that goal ? I don't want want to go and modify every xaml file I have.
Update after first answer
I have tried to put the following setters inside the datatrigger:
<Setter Property="Background" Value="#FFECECF8" />
<Setter Property="CheckBox.IsEnabled" Value="False" />
<Setter Property="DatePicker.IsEnabled" Value="False" />
<Setter Property="ComboBox.IsEnabled" Value="False" />
<Setter Property="TextBox.IsReadOnly" Value="True" />
Unfortunately the tests gave odd results. The IsEnabled property is set for TextBoxes too despite the prefix should limit its application to CheckBoxes, DatePickers and ComboBoxes.
My final need was to make some control contents unchangeable avoiding the difficult to read colors associated with disabled controls. From previous researches I understood that changing the colors for a 'disabled' control is not an easy task and involves the redefinition of the control template. So I thought to apply a combination of IsReadOnly and Background, but it is not applicable for the above problem. In fact CheckBoxes, DatePickers and ComboBoxes can only be made unchangeable using the IsEnabled property.
Am I missing something ?
There is a way, but I have to warn you - this is far from best-practice and should be avoided
WPF allows you to use desired type as a prefix for the property. That way, if you apply the style to a control that doesn't inherit from the prefixed type - the setter is ignored.
<Style x:Key="validationSupport" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="5,2,14,2" />
...OMISSIS...
<Style.Triggers>
...OMISSIS...
<DataTrigger Binding="{Binding DataContext.ActiveWorkspace.Editable, RelativeSource={RelativeSource AncestorType=Window}}" Value="False">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Button.Background" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
[Test this extensively, since I suspect that it might create memory leaks.]

Converter for bound data in style

Can't see the trees through the forest.
Trying a simple databinding and I want to format the value with a converter. (In this converter example, numeric data that is 0 is not displayed.)
Resource:
<conv:FormattingConverter x:Key="FormattingConverter"/>
<Style x:Key="EGTSTextBoxInt" TargetType="TextBox">
<Setter Property="Background" Value="{StaticResource CC_BACKGROUND}" />
<Setter Property="Foreground" Value="{StaticResource CC_FOREGROUND}" />
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}" />
<Setter Property="FontSize" Value="{StaticResource DefaultFontSize}" />
<Setter Property="FontWeight" Value="Normal" />
<Setter Property="FontStyle" Value="Normal" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center"
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Center" />
<Setter Property="IsReadOnly" Value="True" />
</Style>
Textbox:
<TextBox Name="Bill_Item"
Grid.Column="6"
MinWidth="46"
MinHeight="23"
Style="{StaticResource EGTSTextBoxInt}"
Text="{Binding Path=Item, Mode=TwoWay,
Converter={StaticResource FormattingConverter},
ConverterParameter=\{0:G\}}" />
What I want to do is get the Converter code embedded in the style so that I don't have to spell it out in each Text=line.
Adding code behind the XAML to do anything for this is not an option!
I am looking for a pure XAML method.
I am still trying to grasp how certain things are done in Styles.
Brian
There are several ways to do this.
But before you even start:
It's heavy
It's utterly useless in your case
1) Define a custom markup extension
The idea is to inherit from the Binding markup extension that allows you to write Text ="{Binding SomeProperty}".
You can find an example of someone who made his own binding here
This solution does not allow you to put the feature in a style.
2) Define an attached property
that will modify the Binding of the default property of a control (in your case, Text is the default property of TextBox, as you can do <TextBox>my text</TextBox>) in order to use the converter you want, automatically.
This actually allows you to put set this attached property in a style. It is, however, very bad practice. It's as bad a magic strings.
3)Don't do this, just don't.
Write the converter each time.
The Text property of the TextBox is about data. The Style property is about what that data looks like. It doesn't make sense to attach a Converter to a Style.
Edit: I think I see what you're trying to say now. You want Text="{Binding Path=Item}" in one place and <Setter Property="Text" Value="~somehow get the converter in here and have it applied to the existing text property which is bound to Items~" />
As mydogisbox mentioned, I don't think you can split up these ideas in two places like that.
Converters are for converting one value into another value, so they cannot be used without the value they are converting
You can however use StringFormat in your binding to format values without a Converter
<TextBox Text="{Binding Path=Item, StringFormat=G}" />
You could also create a class that inherits from Binding class and sets the default StringFormat, although I feel this is more trouble than it's worth
<TextBox Text="{local:NumberBinding Path=Item}" />
And if you are ever working with Labels instead of TextBoxes, you can apply a style setter to ContentStringFormat, which will apply formatting to the Label's Content
<Style TargetType="{x:Type Label}">
<Setter Property="ContentStringFormat" Value="G" />
</Style>

Attached behaviors and styles

I use an attached behavior that allows a DoubleClick event to be wired to a command in a view model, as in the binding below:
<ListBox Style="{StaticResource MasterListBoxStyle}"
b:SelectionBehavior.DoubleClickCommand="{Binding EditCommand}"
>
I need multiple list boxes for a presentation, all of which will need a DoubleClick wired to an EditCommand.
Can I push this behavior into my MasterListBoxStyle? How?
Cheers,
Berryl
<Style x:Key="MasterListBoxStyle" TargetType="ListBox">
<Setter Property="ItemsSource" Value="{Binding MasterVm.AllDetailVms}" />
<Setter Property="ItemContainerStyle" Value="{StaticResource MasterListingRowStyle}" />
<Setter Property="IsSynchronizedWithCurrentItem" Value="True" />
<Setter Property="AlternationCount" Value="2" />
</Style>
You should be able to add a simple Setter like so in WPF:
<Setter Property="b:SelectionBehavior.DoubleClickCommand" Value="{Binding EditCommand}" />
Assuming the b xmlns is defined in the XAML file that contains your Style.
This won't work in Silverlight though, since Bindings are not supported in Setters. This is something Microsoft is fixing in Silverlight 5.

Resources