I have a View with a NumericUpDown control, which doesn't work like I expect.
Tried Exceed/NumericUpDown and MahApps/NumericUpDown - same problem.
It is defined like this:
<mahapps:NumericUpDown Width="200" Interval="1"
Visibility="{Binding Path=ControlValueQuantityIsVisible, Mode=TwoWay, Converter={StaticResource BoolToVisibilityConverter}}">
<mahapps:NumericUpDown.Value>
<Binding Mode="TwoWay" Path="ValueQuantity" ValidatesOnDataErrors="True" UpdateSourceTrigger="PropertyChanged">
<!-- With or without ValudationRule - same problem -->
</Binding>
</mahapps:NumericUpDown.Value>
</mahapps:NumericUpDown>
It is bound to ViewModel's property ValueQuantity
private double? _valueQuantity;
public double? ValueQuantity
{
get { return _valueQuantity; }
set
{
SetProperty(ref _valueQuantity, value);
CommandOK.RaiseCanExecuteChanged();
}
}
Also, I have a button (Focusable=False) that changes ViewModel's ValueQuantity property to '99'
If I simply press that button, or type values in NumericUpDown, or click its spin buttons - it works fine.
Then I select all text in NumericUpDown's textbox and type '1' over it.
Then I hit the button - and NumericUpDown still shows '1', even though a breakpoint in ValueQuantity setter shows correct value = 99.
Why doesn't NumericUpDown reflect ValueQuantity change in its textbox?
You have to make the button focusable.
The point is that the input field is a TextBox, which by default updates the binding on lost focus: Binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus.
So, you have to make the input field lose its focus in order to trigger the binding. You must move the focus to another focusable element.
Related
When the user has set their Keyboard layout to: Chinese(Traditional,Taiwan) Bopomofo as their input language no binding happens as the user inserts text into the TextBox.
The binding only happens after the user loses focus on the textbox.
EDIT: The binding also triggers,once, when all text is deleted from the textbox, binding a empty string to the property.
In the view
<TextBox Text="{Binding ChineseText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
I tried to set xml:lang="zh-Hant" like so, which made no difference:
<TextBox xml:lang="zh-Hant" Text="{Binding ChineseText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Note: using English(US) keyboard layout, when the user inputs any az-AZ character the bound property gets updated as expected
EDIT: A regular TextChanged event handler fires whenever i input any character, but still nothing is bound to the property.
In my WPF Application, I have created ValidationRules for my TextBoxes so that it will not allow an empty string which works fine and shows a red border with text telling the user it can not be empty. When the application launches, all the fields are blank waiting for input but I still see the red border around them. Is this normal behavior? Note: I would prefer it firing after either a propertychange event or lostfocus event fires when the user using the form not when the form initially loads.
Example of the validation I am doing:
<TextBox x:Name="itemNum" HorizontalAlignment="Left" Height="23" Margin="82,58,0,0" VerticalAlignment="Top" Width="90"
HorizontalContentAlignment="Left" VerticalContentAlignment="Center" PreviewKeyDown="ItemNum_PreviewKeyDown"
PreviewTextInput="ItemNum_PreviewTextInput" TabIndex="0" Validation.ErrorTemplate="{StaticResource validationErrorTemplate}">
<TextBox.Text>
<Binding Path="rxID" Mode="TwoWay" StringFormat="{}{0:#}" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<MY:TextBoxNotEmptyValidationRule x:Name="rxIDValidation" ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
My TextBoxNotEmptyValidationRule Class:
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
string str = value as string;
if (string.IsNullOrEmpty(str))
{
return new ValidationResult(false, "Value CAN NOT BE empty");
}
return ValidationResult.ValidResult;
}
According to your logic, it seems that it is normal. Lets define a bool flag and set it false or true, does not matter, than when application is run and check the flag, if flag value is initial value do not do anything. Beside this, you "if" check needs to check also focused element. If focused element is our textbox and your flag is not initial value so you can change the textblock border.
You can look at the following link :
Validation on Load
Ideally this is the normal behavior in XAML applications if you use IDataErorInfo or INotifyDataErrorInfo . you can use beginInit and EndInit to achieve your desired output.
I Have a text box, depending on the text box value i need to enable/disable other text Boxes.I am using MVVM Pattern.
So here's my problem , whenever i enter some text in TextBox1 ,the Setter for TextBox1 is getting fired and i am able to check in if loop ,whether valus exists and i am disabling other text boxes. Now, when there is single value in text box say "9" and i am deleting / Backspacing it the Set event is not getting triggered in order to enable the other Text Boxes.
View:
<TextBox Text = {Binding TextBox1 , UpdateSourceTrigger = PropertyChanged,Mode= TwoWay}/>
<TextBox Text = {Binding TextBox2 , UpdateSourceTrigger = PropertyChanged,Mode= TwoWay}/>
<TextBox Text = {Binding TextBox3 , UpdateSourceTrigger = PropertyChanged,Mode= TwoWay}/>
View Model:
private int_textBox1;
public int TextBox1
{
get {return _textBox1;}
set
{
_textBox1= value;
if(value > 0)
{
//Code for Disabling Other Text Boxes (TextBox2 and TextBox3)
}
else
{
// Code for Enabling Other Text Boxes (TextBox2 and TextBox3)
}
NotifyPropertyChanged("TextBox1");
}
}
If you are using MVVM pattern, you should create boolean properties, and bind TextBox.IsEnabled property to it. Your boolean properties should raise PropertyChanged event, in order to tell the view (TextBox in your case) that your property was really changed:
public bool IsEnabled1
{
get { return _isEnabled1; }
set
{
if (_isEnabled1 == value)
{
return;
}
_isEnabled1 = value;
RaisePropertyChanged("IsEnabled1");
}
}
and then in xaml:
<TextBox Text="{Binding TextBox1, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
IsEnabled="{Binding IsEnabled1}" />
and so on with other TextBoxes
first of all, if you set your updatesourcetrigger to Propertychanged - your setter is called when you do anything in your textbox. i check this in a simple testproject. btw do you call OnPropertyChanged in your setter, because its not in your sample code?
if not your binding seems to be broken. so pls check your binding or post some more relevant code.
EDIT:
if you change your type to int? you can do the following xaml
<TextBox Text="{Binding MyNullableInt, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, TargetNullValue=''}"/>
Basically I have two textboxes which binds to two columns of a ListView. When the user select one row in the ListView, the values will be displayed in the textboxes. This has no problem.
The user can edit the text of one TextBox, the other TextBox is not editable. The text of the second TextBox is based on the text of the first TextBox. For example, the first box is product price in Chinese yuan and second box is product price in British pound. The exchange rate is from setting. The user can only edit value of Chinese yuan, but not British pound. The sold price is initially from database.
My purpose is when the user change the first TextBox, then in the text_changed event, I calculate the value for the second TextBox.
When the end user change selection to the ListView, It seems to me the binding to GoodsSoldPriceCN happened first, then this triggered the text_changed event. In the event handler, I calculate the sold price in pound for the second TextBox and this two-way binding will update source. The problem is this wouldn't update the row the user just selected, but update the row the user previously selected.
So, my question is how can I achieve this requirement.
Two textboxes bind to the selection of a row of a ListView.
The second text box also bind to the text of the first box when the user manually change the text of the first TextBox.
My code is as follows:
XAML
<TextBox Grid.Row="2" Grid.Column="1" HorizontalAlignment="Stretch" Name="GoodsSoldPriceCN" Style="{StaticResource textBoxInError}" TextChanged="GoodsSoldPriceCN_TextChanged">
<TextBox.Text>
<Binding Path="soldpricecn" ConverterCulture="zh-cn">
<Binding.ValidationRules>
<ValidationRules:MoneyValueRule Min="1" Max="100000"></ValidationRules:MoneyValueRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<TextBox Grid.Row="3" Grid.Column="1" HorizontalAlignment="Stretch" Name="GoodsSoldPriceGB" IsEnabled="False" Style="{StaticResource textBoxInError}" Text="{Binding Path=soldpricegb, Converter={StaticResource MoneyValueConverter}, UpdateSourceTrigger=PropertyChanged, ConverterCulture=en-gb}" />
Code
private void GoodsSoldPriceCN_TextChanged(object sender, TextChangedEventArgs e)
{
isDirtyOrder = true;
ListViewItem item = e.OriginalSource as ListViewItem;
try
{
if (!String.IsNullOrEmpty(GoodsSoldPriceCN.Text))
GoodsSoldPriceGB.Text =
(decimal.Parse(GoodsSoldPriceCN.Text) / decimal.Parse (Properties.Settings.Default.ExchangeRate)).ToString();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
...
}
I use Binding.SourceUpdated event instead of TextChanged event and that solve the problem.
I have several controls including a DataGrid that I want to be disabled until there is a valid value in the first TextBox in the presentation. So I added a boolean property to bind to in the VM and bind to it in the xaml (below).
The binding works, but has the side effect of 'trapping' the user in the TextBox (MoneyToAllocate).
Presumably this is because the TB binding is LostFocus and there is no place for the focus to go and actually trigger the updates. What's a good way to fix this?
Cheers,
Berryl
ViewModel
public bool HasMoneyToAllocate { get { return MoneyToAllocate.Amount > 0; } }
public Money MoneyToAllocate {
get { return _moneyToAllocate; }
set {
if (value.Amount < 0) return;
_moneyToAllocate = new Money(value.Amount, SelectedCurrency);
NotifyPropertyChanged(() => HasMoneyToAllocate);
}
}
View
<TextBox Text="{Binding MoneyToAllocate, Converter={StaticResource moneyConverter}}" />
<DataGrid IsEnabled="{Binding HasMoneyToAllocate}" ...
EDIT
I should have added that I tried PropertyChanged for update but it gets a bit messy since the value of the text box needs to be formatted by the converter. Any other ideas?
FINAL EDIT
I wound up letting another control that previously wasn't a tab stop be a tab stop, so the text box had a place to go. Phil understood the problem best and gets the answer, even though the range of values the user can input (.001 to decimal.MaxValue) make an up-down impractical.
Use UpdateSourceTrigger=PropertyChanged
<TextBox
Text="{Binding MoneyToAllocate, UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource moneyConverter}}" />
Then you have to use UpdateSourceTrigger=PropertyChanged
- if you use that binding you are using the value in the VM will not effected till the focus moves from the textBox
- but if you add UpdateSourceTrigger=PropertyChanged to your binding the VM property (MoneyToAllocate) will effected immediately (when the textBox.Text value changed)