WPF validation without updating the data source - c#

I have a TextBox displaying the time part of a DateTime:
<TextBox HorizontalAlignment="Left" Height="23" Margin="0,13,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Validation.Error="Validation_OnError">
<TextBox.Text>
<Binding Path="MyDate" StringFormat="HH:mm" NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<c:TimeValidator></c:TimeValidator>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Is it possible to do the validation on property change, and the conversion on lost focus?
I want to have the validation on property changed, but I want to have my data source updated on lost focus. Otherwise, the converter will kick in while the user is editing in the TextBox. This might be a problem if the values is 10:50 and the user deletes the last number, so that the value becomes 10:5. The converter will then convert this to 10:50. This is okay to do on lost focus, but not on property changed. But for the sake of the validator, i want to validate on property change so the user have the red border as long as the entered value is not valid.

Yes! I was just wrestling with this. AFAIK, there is no XAML combination for this--it must be done in the codebehind, and you need a direct reference to the element.
Element.GetBindingExpression(PropertyName).ValidateWithoutUpdate();
You'll probably want to check that GetBindingExpression doesn't return null; this will run any converters you have attached (presumably to supply the converted value to converters with ValidationStep set to ConvertedProposedValue), but will not update the source. And, of course, you'll have to call this in some event, perhaps TextChanged or somesuch. Here is the MSDN documentation for it: https://msdn.microsoft.com/en-us/library/system.windows.data.bindingexpressionbase.validatewithoutupdate(v=vs.110).aspx

Use this code:
BindingExpression expression =
txtStudentName.GetBindingExpression(TextBox.TextProperty);
expression.ValidateWithoutUpdate();
If you want to update it's source after check use this code:
BindingExpression expression =
txtStudentName.GetBindingExpression(TextBox.TextProperty);
expression.ValidateWithoutUpdate();
if (expression!=null && !expression.HasError)
expression.UpdateSource();

Related

Doing all my validation in the ViewModel

How can I stop the UI layer from performing its conversion validation, or at least have it continue on? If I have a textbox bound to a DateTime:
// view
<TextBox x:Name="StartTimeTextBox">
<TextBox.Text>
<Binding Path="StartTime"
StringFormat="t"
NotifyOnValidationError="True"
ValidatesOnDataErrors="True"
ValidatesOnExceptions="True" >
<Binding.ValidationRules>
<va:AlwaysSucceedsValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
// view model
[MyValidationAttribute]
public DateTime StartTime {get; set;}
When the user selects all the text text in the textbox and deletes it (or types in "asdf"), the conversion fails, it gets a red border and validation stops. I've tried using ValidatesOn... attributes (which I thought would allow my "MyValidationAttribute" to execute) without success. I've also tried adding a ValidationRule that always returns true no matter what the Text - but nothing works.
If you bind TextBox.Text to a DateTime, and the user types in "my hovercraft is full of little lambs", what can the Binding possibly assign to your viewmodel property for you to validate? There's nothing it can do.
You can set Validation.ErrorTemplate for the TextBox to an empty template, and that'll get rid of the red outline business, but you still won't get anything validatable in your viewmodel property.
If you want to validate string input from the user as a valid or invalid date, you're going to have to do that at some point where you have the raw string input in your hands.
If you want to do it in your viewmodel, that means giving your viewmodel a string property for StartTime, and binding that to the TextBox. Call it StringStartTime; in its setter, if the string is valid it sets DateTime StartTime; if not valid, it leaves StartTime alone but sets some error property, or throws an exception, or whatever.

Text box not showing Red Validation Error in WPF

We are currently writing a GUI application using WPF and .Net4.5.
One of our pages contains a TabControl with custom UserControls as TabItems. These UserControls just contain a list of editable TextBoxes. The Textboxes have a custom ValidationRule that validates the text based on a regular expression. The issue is that these editable text boxes are bound to Properties that get loaded at startup with default values from a text file/database.
I need validation to occur before a text box has focus, or before it is edited, to ensure that the values that were entered in the text file/database were entered correctly. Currently, when I select a tab item the text boxes are not displaying the red validation error box, even though it seems validation is running correctly. Only after I click an item with a Validation error do I see the associated red box.
I am using UpdateSourceTrigger="PropertyChanged" and I can debug and see that the validation code is running at the correct time, but still the red boxes will not display. I even added code to re-fire the 'Property changed' events on the bound properties whenever the TabItem gains focus - but this still does not help. Here is an example of one of the TextBoxes that is not showing the validation:
<TextBox x:Name="TextBox1" Margin="10,5,5,5" Width="150" MaxLength="5" Style="{StaticResource ServiceEntryTextBox}">
<TextBox.Text>
<Binding Path="TexBox1BoundProperty" Converter="{StaticResource DoubleConverter}" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<validation:StringRegexFormatValidation RegexPattern="^[0-9]{0,1}.{0,1}[0-9]{1,3}$" ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Is there another piece I am missing?
Can you try placing your TextBox inside an AdornerDecorator? I need to dig out the source for this but I have seen issues before where controls inside a Tab control do not render the validation correctly.
e.g.
<AdornerDecorator>
<TextBox x:Name="TextBox1" Margin="10,5,5,5" Width="150" MaxLength="5" Style="{StaticResource ServiceEntryTextBox}">
<TextBox.Text>
<Binding Path="TexBox1BoundProperty" Converter="{StaticResource DoubleConverter}" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True">
<Binding.ValidationRules>
<validation:StringRegexFormatValidation RegexPattern="^[0-9]{0,1}.{0,1}[0-9]{1,3}$" ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</AdornerDecorator>
Further help for debugging
I have also seen issues when binding directly to a DependencyProperty. The issue I saw was I was raising INotifyPropertyChanged in order to trigger the validation to be processed (which worked fine in .NET 4.0) however since .NET 4.5 you cannot use INotifyPropertyChanged for triggering validation on a DependencyProperty.

Using WPF validation

I have a dialog in my project that the user enters some values in and when he hits OK I add an item to my database. I am using Entity Framework, so my adding to database code is something like this:
TransactionItem _item = new TransactionItem();
_item.DoctorID = (int)cmbDoctor.SelectedValue;
_item.TransactionCategoryID = (int)_dlg.cmbCat.SelectedValue;
_item.TransactionMethodID = (int)_dlg.cmbMethod.SelectedValue;
_item.Amount = int.Parse(_dlg.txtAmount.Text);
_item.DocumentID = _dlg.txtDocNum.Text;
_item.Info = _dlg.txtInfo.Text;
_item.Date = _dlg.dteDate.SelectedDate.ToString();
_db.TransactionItems.Add(_item);
_db.SaveChanges();
But the problem is there is nothing to bind and enable validating. I have tried making an empty object in my window and bind text box to it, but it had its own problems and didn't work as expected. I just want to when users enter values or when he hits OK, check if all of fields are valid (for example one of problems was if the user didn't enter any value, it is still valid even though the stringnotnull validator is enabled, but the most important problem was that it automatically set the textbox's text to null and mark it as a null value).
And I have made my own validator and here is a example of how I implemented them on one of my textboxes:
<TextBox Name="txtAmount" HorizontalAlignment="Left" Height="23" Margin="83,169,0,0" VerticalAlignment="Top" Width="224" Tag="T">
<TextBox.Text>
<Binding Path="myitem" ElementName="myWindow" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<Validators:StringNullValidationRule/>
<Validators:IsNumericValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Why don't you create a property in your viewmodel for each value the user needs to enter, and bind to it? Then you could use these properties when adding an item. For example:
ViewModel:
public int Amount { get; set; }
...
public void AddItem()
{
TransactionItem _item = new TransactionItem();
// ...
_item.Amount = Amount;
}
XAML:
<TextBox Name="txtAmount" HorizontalAlignment="Left" Height="23" Margin="83,169,0,0" VerticalAlignment="Top" Width="224" Tag="T">
<TextBox.Text>
<Binding Path="DataContext.Amount" ElementName="myWindow">
<Binding.ValidationRules>
<Validators:StringNullValidationRule/>
<Validators:IsNumericValidationRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
I also recommend having a look at the INotifyDataErrorInfo interface (or the IDataErrorInfo interface if you're using .NET 4.0 or lower) to implement validations.
Use the IDataErrorInfo interface. You can implement it in your ViewModel or your Model class depending on your design. An example of how you can do it is in WPF: Validation made easy with IDataErrorInfo.
And I recommend you read this great Josh Smith article: WPF Apps With The Model-View-ViewModel Design Pattern. There you can see a good example of validation.

WPF Activate binding OnTextInput on textbox

I have a textbox with the following binding :
<TextBox Binding={Path=MyStr, Mode=TwoWay}>
My problem is that the binding only fires when the textbox loses focus and not for each char the user enters.
The textbox also has an OnTextInput function that fires properly but how do I activate the binding in the code behind?
*I'd rather doing it in a pure mvvm way (not use the window's code behind if possible)
Any answer will be accepted mvvm or not.
Here:
<TextBox Text="{Binding Path=MyStr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
now your bound property will be changed on each character.
U can use the updatesource trigger and set it to property changed
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
The moment it is changed it will sent it's updated value back to your DataContext
on msdn:
http://msdn.microsoft.com/en-us/library/system.windows.data.updatesourcetrigger.aspx
There is a UpdateSourceTrigger Called PropertyChanged, if you use that as your update trigger when you change the text of the textbox it will fire and in your binding property setter you can perform what ever action you need to happen as text changes.
<TextBox Text="{Binding Path=Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

Custom ValidationRules inside Expander.Header Binding not firing

I am having trouble getting a custom ValidationRule to fire, when it is associated with an Expander.Header binding. In fact, the only place I can seem to get these custom rules to fire is in a DataGrid.RowValidationRules block...
The expander is defined in my Window XAML file like so;
<Expander Style="{StaticResource ValidatedSecondLevelExpanderStyle}">
<Expander.Header>
<Binding Path="Name" Mode="OneWay" ValidatesOnDataErrors="True" NotifyOnValidationError="True">
<Binding.ValidationRules>
<ValidationRules:BoundObjectIsValid />
</Binding.ValidationRules>
</Binding>
</Expander.Header>
</Expander>
The bound property 'Name' is displayed correctly, but the validation rule 'BoundObjectIsValid' does not get invoked. Is this possible, and if so, what am I missing?
I know that I could alternately implement IDataErrorInfo on the bound object, however the object can't sensibly validate itself without some context that is provided by other parts of the system. Refactoring is possible, but I'd love to get the ValidationRules to work first!
Refer to the msdn.
The binding engine checks each ValidationRule that is associated with a binding every time it transfers an input value, which is the binding target property value, to the binding source property.
So here in your case, you don't have an inpurt value being transfered to the source property since your Expander.header is not a control which you can use to input values.
Edit: But there is a property named ValidatesOnTargetUpdated' in the ValidationRule. When setting it to true, the validationrule will be applied when the target property is updated

Categories

Resources