How to disable validation when TextBox property IsEnabled is false? - c#

I found various answers on StackOverflow, and none of them helped me.
I want turn off validation on TextBox when IsEnabled="false"
What am I missing here?
<TextBox x:Name="idTxtBox">
<!--This is where I tried to disable validation-->
<TextBox.Style>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
<!--I want to disable these validation rules-->
<TextBox.Text>
<Binding Path="ID" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<val:RequiredFieldValidation ValidationStep="RawProposedValue"/>
<val:IsNumberValidation Min="1" Max="250" ValidationStep="ConvertedProposedValue"/>
<val:UniqueIDTag ValidationStep="RawProposedValue"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
<Validation.ErrorTemplate>
<!--........-->
</Validation.ErrorTemplate>
</TextBox>

Without a good Minimal, Complete, and Verifiable code example showing exactly how your code works, and a more specific explanation of what you want the code to do and why your current approach doesn't accomplish that, it's hard to know for sure what answer would serve you best. However, it seems to me that you're on the right track, you're just changing the wrong property.
I would not expect removing the ErrorTemplate value to affect whether validation occurs, just what the user sees. If you want to remove the validation, you should do just that: remove the validation. For example:
<TextBox.Style>
<p:Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<p:Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Text" Value="{Binding ID}"/>
</Trigger>
</p:Style.Triggers>
</p:Style>
</TextBox.Style>
(Ignore the p: namespaceā€¦I just put that in there so that the code formatter Stack Overflow is using won't get side-tracked by the Style element name.)
In other words, the validation is included in the binding. So, when you don't want the validation to occur, change the binding to one without validation (and since the control is disabled, you can omit the UpdateSourceTrigger value as well).

Related

How to remove a dictionary resource reference from a TextBlock?

I have this element:
<TextBlock Style="{StaticResource textReplyMessageStyle}">
<Run x:Name="answerMessage" Text="{Binding Message, Mode = OneWay, FallbackValue = ''}" />
</TextBlock>
And I have the need to print in answerMessage either the content of the var Message (thanks to the binding) or an element from the dictionary (thanks to resource reference done by the code below).
answerMessage.SetResourceReference(Run.TextProperty, "Answer_Message_Not_Selected");
The binding is fully working as well as the dictionary reference, but after setting the resource reference once I can not find a way to make the binding work again.
I tried to re-do the binding programmatically but is not working...
The only working workaround I found is to set programmatically the text of answerMessage.
How can I remove the resource reference from the Run element and make the binding work again?
Just to give a bit of context the variable Message contains a number and the resource Answer_Message_Not_Selected
contains the text "Not selected" or a translation in a different language depending on the dictionary active on the program. I have to use dynamic resource reference because the language of the program can be changed on the fly.
Thanks!
A simple way to work this around is to make the output of the TextBlock depends mainly on the Message property.
For example, you can bind the value of Text to Message only if the value of Message is not null, otherwise set it to your resource:
<TextBlock Style="{StaticResource textReplyMessageStyle}">
<Run x:Name="answerMessage" >
<Run.Style>
<Style TargetType="{x:Type Run}">
<Setter Property="Text" Value="{Binding Message, Mode = OneWay, FallbackValue = ''}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Message}" Value="{x:Null}">
<Setter Property="Text" Value="{StaticResource Answer_Message_Not_Selected}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Run.Style>
</Run>
</TextBlock>
Notice that you should set the starting value of Text inside the style because properties set in the control initializer will override any style setters!
Another thing you can do instead of setting the value of Message to null is to add a property AnswerMessageSelected in the view model, to be more explicit when the TextBlock should change its target value:
<TextBlock Style="{StaticResource textReplyMessageStyle}">
<Run x:Name="answerMessage" >
<Run.Style>
<Style TargetType="{x:Type Run}">
<Setter Property="Text" Value="{Binding Message, Mode = OneWay, FallbackValue = ''}" />
<Style.Triggers>
<DataTrigger Binding="{Binding AnswerMessageSelected}" Value="False">
<Setter Property="Text" Value="{StaticResource Answer_Message_Not_Selected}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Run.Style>
</Run>
</TextBlock>
And generally after using this method, it might not be necessary to use x:Name to refer to in the code behind, since it's a better practice to let the ViewModel do all the work and not the code behind the View:
<TextBlock>
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource textReplyMessageStyle}">
<Setter Property="Text" Value="{Binding Message, Mode = OneWay, FallbackValue = ''}" />
<Style.Triggers>
<DataTrigger Binding="{Binding AnswerMessageSelected}" Value="False">
<Setter Property="Text" Value="{StaticResource Answer_Message_Not_Selected}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
My initial suspicions were correct, thanks to #Jason Tyler #o_w for confirming that.
When you set a reference to a Run (and also for similar elements) you lose the binding property.
The solution to my problem is simply to do the binding again.
Binding b = new Binding();
b.Path = new PropertyPath("Message");
b.Source = this;
BindingOperations.SetBinding(answerMessage, Run.TextProperty, b);
This solution fixes the problem, but it is possible to fix the cause by setting the Answer_Message_Not_Selected resource to the bonded Message element.
Message = Application.Current.Resources["Answer_Message_Not_Selected "].ToString()
If the resource is dynamic, like in my case, you will need some sort of OnChange event observing the resource (or dictionary) to keep the content of Message always updated.

using triggers as resources

I want to define triggers as resources to use them later in my controls.
Like this:
<Window.Resources>
<DataTrigger x:Key="Trigger1" Binding="{Binding ViewModelProperty1}" Value="Val1">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger x:Key="Trigger2" Binding="{Binding ViewModelProperty2}" Value="Val2">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
...
</Window.Resources>
However, when I try to run the code, the compiler complains that IsEnabled is not a valid member. I think this is because it cannot know if the control in question will even have the property "IsEnabled". Like with styles, I think I need to somehow specifiy the TargetType (which would be, in my case, FrameworkElement). But how?
NOTE:
Please do not suggest to use styles instead of triggers as resources. Since a control can only have ONE style, but I need to give SEVERAL triggers to one control, styles are no option here:
In my actual code I have a Button that should have trigger 1, 2 and 4 and a TextBox that should have trigger 1 and 3 and a Label that should have trigger 2, 3 and 4... I think you get it.
You can do it like this (note how I prepend IsEnabled with FrameworkElement and also how I reference those resources from style triggers):
<Window.Resources>
<DataTrigger x:Key="Trigger1"
Binding="{Binding ViewModelProperty1}"
Value="Val1">
<Setter Property="FrameworkElement.IsEnabled"
Value="False" />
</DataTrigger>
<DataTrigger x:Key="Trigger2"
Binding="{Binding ViewModelProperty2}"
Value="Val2">
<Setter Property="FrameworkElement.IsEnabled"
Value="False" />
</DataTrigger>
</Window.Resources>
<Button>
<Button.Style>
<Style>
<Style.Triggers>
<StaticResource ResourceKey="Trigger1" />
<StaticResource ResourceKey="Trigger2" />
</Style.Triggers>
</Style>
</Button.Style>
</Button>

Binding to value of property from inside style template failing

I'm having an issue with attempting to bind the Fill property of an Elipse (in a ToggleButton control) to a custom DependencyProperty of another control.
Below is the XAML code raising the "Property path is not valid" error - It's a Resource dictionary file for the Expander control.
The erroneous line:
Value="{Binding Path=(local:Expander.ToggleButtonMouseoverColor)}"
The first code block - the MixSelectorExpanderButtonStyle is attached to a style definition for an expander, seen in the second code block.
<Style x:Key="MixSelectorExpanderButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="Circle" Property="Fill" Value="{Binding Path=(local:Expander.ToggleButtonMouseoverColor)}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm confident the property is correct - in the same file, I am able to access the ToggleButtonMouseoverColor property without error:
<Style TargetType="{x:Type local:Expander}">
<Style.Triggers>
<Trigger Property="Status" Value="0">
<Setter Property="ToggleButtonMouseoverColor" Value="{DynamicResource ZKGeneric_Highlight_MouseOver}" />
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Expander}">
<ToggleButton style=""{StaticResource MixSelectorExpanderButtonStyle}" />
</ControlTemplate>
</Setter.Value>
</Setter.Value>
</Style>
When I remove the local: prefix from the path, the error changes to the property not being recognized or accessible.
If I name the style definition and change the binding to:
Value="{Binding Path=ExpanderStyle.ToggleButtonMouseoverColor}"
I am able to build and run it, however it appears to just be a null value.
Clearly I'm missing some syntax to properly point to the property, but this is the first time i have attempted to bind in such a convoluted manner.
If not, is there a more optimal way to define this behaviour?
Any help would be appreciated, in the meantime, I shall attempt to consult my WPF programmer's reference.
EDIT:
I forgot to mention, I have also been trying to use Value="{Binding ToggleButtonMouseoverColor, RelativeSource={RelativeSource TemplatedParent}}", among other variations, but can't seem to get it working.
I believe you want this, although it sounds like you've potentially tried it? I have no idea why it wouldn't work...
Value="{Binding ToggleButtonMouseoverColor, RelativeSource={RelativeSource AncestorType={x:Type local:Expander}}}"

Binding an empty string if value is non-null in wpf

I would like to make a WPF usercontrol that shows a string when and only when the datacontext == null. I'm using the TargetNullValue attribute in binding to display a custom string when the datacontext is null, and that's working as intended. But when the datacontext is non-null, it just shows the ToString value, which I would like to get rid of.
Of course I could solve this easily by using a valueconverter, but I'd like to find a way to solve this with xaml only. Does anyone know a way to do it?
In case you want TextBlock to be shown only in case binding value is null, you can have trigger in place and set Visibility to Visible when binding value is null and otherwise Collapsed always.
<TextBlock Text="{Binding TargetNullValue=NullValue}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
Use a data trigger on {x:Null}. There are many options using styles, data templates etc., depending on taste and needs. For instance:
<DataTemplate x:Key="ShowOnNull">
<TextBlock x:Name="text"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding}" Value="{x:Null}">
<Setter TargetName="text" Property="Text" Value="your custom string"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
...
<ContentPresenter ContentTemplate="{StaticResource ShowOnNull}"
Content="{Binding ...}"/>

problem in the textblock style

Hello I am trying to make a textblock that they should focus on the event to underline the text and add when you lose the focus off him.
this is possible?
While I'm not sure if this is supported in Silverlight, this is how you'd do it in WPF:
<xxx.Resources>
<Style x:Key="HoverUnderline" TargetType="TextBlock">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="TextDecorations" Value="Underline"/>
</Trigger>
</Style.Triggers>
</Style>
...
<TextBlock Style="{StaticResource HoverUnderline}"
Content="Point at me to underline."/>
(Another interpretation of your question: use IsFocused instead of IsMouseOver. That's a weirder interpretation though since normally text blocks can't receive focus.)

Categories