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.
Related
I use C# WPF in Visual Studio 2019
I want to display my TextBoxes values as Thousands decimal separated like this 1500.9 => 1,500.9
I Choose Validation Rules and Binding for this problem because I don't want to use C# Code Behind and Another point is that this option alone does nothing for a text box
StringFormat="0,0.0"
What is My Problem :
I thought Binding in Validation Rule uses this type of property for formatting ,
I did bind all of my textboxes to my property and now all text boxes have the same value even when I change one of them
enter image description here
My Project :
here is my Model name as Validator.cs :
namespace WpfApp5
{
public class Validator
{
public double dbl_numeric { get; set; }
}
}
My window for binding textboxes :
<Window x:Class="WpfApp5.Budget_Default"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp5"
mc:Ignorable="d"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:validate="clr-namespace:WpfApp5.Validation"
AllowDrop="True"
Height="550" Width="1033" >
<Grid x:Name="mygrid">
<TextBox x:Name="TextBox1" >
<Binding Path = "dbl_numeric" UpdateSourceTrigger = "PropertyChanged" StringFormat="0,0.0">
<Binding.ValidationRules>
<ExceptionValidationRule ValidatesOnTargetUpdated = "True"/>
<validate:RequeredViladation/>
</Binding.ValidationRules>
</Binding>
</TextBox>
<TextBox x:Name="TextBox2" >
<Binding Path = "dbl_numeric" UpdateSourceTrigger = "PropertyChanged" StringFormat="0,0.0">
<Binding.ValidationRules>
<ExceptionValidationRule ValidatesOnTargetUpdated = "True"/>
<validate:RequeredViladation/>
</Binding.ValidationRules>
</Binding>
</TextBox>
<TextBox x:Name="TextBox3" >
<Binding Path = "dbl_numeric" UpdateSourceTrigger = "PropertyChanged" StringFormat="0,0.0">
<Binding.ValidationRules>
<ExceptionValidationRule ValidatesOnTargetUpdated = "True"/>
<validate:RequeredViladation/>
</Binding.ValidationRules>
</Binding>
</TextBox>
</Grid>
What I need :
How to use Validation Rule or something to Display Thousands of Separated decimal numbers to use strings format for my textboxes
long story short : Each textbox should be separated into 3 digits, 3 digits for its own value only
1500.9 => 1,500.9
If all you want is to format the value bound to the textbox, this would suffice:
<TextBox Text="{Binding Path=dbl_numeric,StringFormat={}{0:N2}}" />
This will give you a culture specific separator for thousands, and two decimal places.
Validation is another topic. Note that out of the box, WPF will check if a value can be parsed as a double, and put a red border around a textbox if, for example, you input text. You may want to set UpdateSourceTrigger to LostFocus if you want to allow a user to type in a complete value before validating. If you have other validation needs, you will have to manually add this.
You three text boxes are currently all bound to the same value in the model (which typically would be a view model 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.
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();
Hello I have question about a wpf/xaml text box c# implementation.
I am trying to figure out how in my c# code to know what the UpdateSourceTrigger is being used.
I am a newbie, so I would very much appreciate if people are patient with me and helpful.
In my C# I need to know how the data in the Text box is trying to be accessed using UpdateSourceTrigger. I know the property changed when my OnPropertyChanged() is called. But I also need to know how if the user is trying to use LostFocus or PropertyChanged in the C# code. This is so I can do some special processing for either case.
xaml
<TextBox>
<TextBox.Text>
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
c#
protected void OnPropertyChanged(string name)
{
// If UpdateSourceTrigger= PropetyChanged then process one way
// If UpdateSourceTrigger= LostFocus then process one way
}
Is there any other methods that get called when using LostFocus?
Thanks you
You will have to get a reference to your TextBlock and get the binding expression then you will have access to the Binding information
Example:(no error/null checking)
<TextBox x:Name="myTextblock">
<TextBox.Text>
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
var textblock = this.FindName("myTextBlock") as TextBlock;
var trigger = textblock.GetBindingExpression(TextBlock.TextProperty).ParentBinding.UpdateSourceTrigger;
// returns "PropertyChanged"
another way of getting the binding object is:
Binding binding = BindingOperations.GetBinding(myTextBox, TextBox.TextProperty);
if (binding.UpdateSourceTrigger.ToString().Equals("LostFocus"))
{
}
else
{
}
Is there a way to template Binding.Converter and Binding.ValidationRules within a style?
Eg: I have the following textbox:
<TextBox x:Name="DepartTime" Height="23" HorizontalContentAlignment="Left" HorizontalAlignment="Left"
Margin="3" Width="140"
Style="{DynamicResource TimeOfDayTextBox}">
<TextBox.Text>
<!-- Textbox notifies changes when Text is changed, and not focus. -->
<Binding Path="FlightDepartTime" StringFormat="{}{0:hh:mm tt}" >
<Binding.Converter>
<convert:TimeOfDayConverter />
</Binding.Converter>
<Binding.ValidationRules>
<!-- Validation rule set to run when binding target is updated. -->
<validate:ValidateTimeOfDay ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
.. I can't figure out how to incorporate the Converter and the Validation rule into my TimeOfDayTextBox style.
Many Thanks.
Unfortunately, no. The style could only set the Text property itself to a Binding. It cannot set attributes of the binding. Also, since Binding is not a DependencyObject there is no way to style a binding.
One option you have to make your code more concise is to use a custom MarkupExtension that creates the binding you want:
public class TimeOfDayBinding
: MarkupExtension
{
public PropertyPath Path { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var binding = new Binding()
{
Path = Path,
Converter = new TimeOfDayConverter(),
};
binding.ValidationRules.Add(new ValidateTimeOfDay()
{
ValidatesOnTargetUpdated = true,
});
return binding.ProvideValue(serviceProvider);
}
}
Given your control names, you may also want to use a time picker control instead of a TextBox. Check out this question: What is currently the best, free time picker for WPF?
A style can contain only a common set of property which can be applied to multiple controls. In your case, the converter and the validation rule aren't applied to the textbox, but to the content of the binding, so they are specific for a single element and cannot be used in a style.