I have code like this, in pagefunction making up a wizard:
<TextBox Name="txtDate" Text="{Binding Path=Date}"></TextBox>
The user types in and clicks next, object sent to next page with this data.
But if I set
<TextBox Name="txtDate" Text="{Binding Path=Date, TargetNullValue='2010-01-15'}"></TextBox>
So I can have some "example" text in the box already, and the user hits next to accept this without changing it, no value is passed in the object to the next pagefunction. If the user changes it then it works as usual.
So how can I have some default text without stopping the data being sent on?
You could set an initial value on the date that you are binding to.
If the Date property is a dependency property when you create it you can give it an inital value. Then you could attach a handler to notify you when it changed, and mark a flag as non intial value. (so you know its changed)
If you're providing a true data default (i.e. one that is a valid data value) consider initializing your data-bound object to that value.
Related
I have a TextBox that I want to bind to two sources (source A and source B).
I want to display source A when that gets updated and source B when the user provides input.
I don't want to display the data from both sources at the same time.
I tried using a priority binding, but that doesn't appear to work the way I want it to.
<TextBox>
<TextBox.Text>
<PriorityBinding>
<Binding ElementName="Features_ComboBox" Path="SelectedItem.Address" Mode="OneWay" />
<Binding Path="UserAddress" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay"/>
</PriorityBinding>
</TextBox.Text>
<TextBox>
Ideally the textbox will be updated when the "Features_ComboBox" selected item changes, but if the user writes in the textbox it will update the "UserAddress" property (hence the mode settings).
What happens instead is that the "Features_ComboBox" updates the textbox but the UserAddress never gets updated.
I also tried using MultiBinding, but i was less successful with that.
Any ideas how to do this?
From the documentation:
The binding engine starts with the first binding in the list and verifies whether that binding returns a value successfully; if it does, the value from that binding is used. If the first binding does not return a value successfully, the binding engine examines the second binding to determine whether it returns a value successfully; if it does, the value from the second binding becomes the active value. This verification process continues to the end of the list of bindings. If none of the bindings returns a value successfully, the binding uses the FallbackValue.
The binding engine continues to listen for changes on all bindings. If at any point one of the bindings that has a higher priority returns a value successfully, the value for that binding becomes the active value and replaces the current value.
Note that the selection of the Binding to use is based solely on updates to the source of the binding. If the source doesn't change, the active binding isn't changed. Furthermore, in your own example, even if the source property UserAddress had changed, that binding would still not become active because you placed the Binding object at a lower priority than the ComboBox binding.
The PriorityBinding object will always prefer the higher-priority, i.e. earlier-ordered, binding in its list. As long as that binding is producing a value, no other binding will be selected.
The PriorityBinding object simply does not have the behavior you want. It's for a completely different kind of scenario.
I recommend that you solve the problem in the view model. For example, you can bind the ComboBox and the TextBox to separate view model properties. Then in the view model, if and when the ComboBox selection is modified, you can explicitly copy that data to the TextBox's source property, which will then update the TextBox.Text property.
I sometimes use a DataContext binding on UserControls and Panels when all the child controls show data from the same object. But if I set that property to a new instance of of an object where the two objects are Equal (as in their Equals method returns true), the controls don't rebind to the new object. They seem to continue to display and update the data from the previous object.
In the example below, the CurrentDeal property is a Deal object which implements a custom Equals method that returns true when the two Deals have the same unique database identifier. When setting CurrentDeal, the setter does not check equality. It always sets the value and raises a PropertyChanged event.
<Grid DataContext="{Binding CurrentDeal}">
<TextBox Text="{Binding Price, Mode=TwoWay"} />
</Grid>
private Deal _currentDeal;
public Deal CurrentDeal
{
get { return _currentDeal; }
set
{
_currentDeal = value;
NotifyPropertyChanged(nameof(CurrentDeal));
}
}
If I set a completely different Deal, then the textbox shows the new Deal's Price, and updating the value in the text box updates the Price on the new Deal as expected.
But if I set it to a newer instance of the "same" Deal (same in that their Equals methods return true), then the text box continues to show the old value (the Price may have changed since the last time this Deal was displayed). Also, changing the value in the text box doesn't update the new Deal's Price (I haven't tested if it updates the old Deal's Price, but I'm guessing that's what's happening).
But, if I were to do this instead, everything works as expected.
<Grid>
<TextBox Text="{Binding CurrentDeal.Price, Mode=TwoWay"} />
</Grid>
Obviously, if I could do that everywhere I would, but my problem comes when using reusable UserControls. I have to set the DataContext if a UserControl is to be bound to the same object but in different View/View Models.
I also can't just refresh the old entity because these are Entity Framework entities from different contexts. This came about when switching towards a "new context for every request" solution, rather than an "each VM gets its own context" solution.
I'm honestly not really sure what my question is... this seems like a bug in the DataContext binding. I don't think it should be taking equality into account. When a PropertyChanged event is fired on the property, it should always bind to the current data, right?
But can anyone see if I'm missing something here? Anyone ever had to deal with this before?
I bound my WPF form to a class's property that is Decimal. The textbox automatically higlighted in red if the user enter invalid format (string instead of decimal). However, I want to make it more secure by validating before storing the inserted data into database.
The problem is, whenever a user enter a non decimal value, the binding will return 0 instead of null or error. So it managed to get into the database without second level validation.
What is the best way to validate a WPF binding to a decimal? Right now it wont return null so I do not have any means to capture the error.
Here is how I bound the textbox
<TextBox x:Name="stockTxtBx" Grid.Row="3" Grid.Column="1" Style="{StaticResource StandardBox}" Text="{Binding StockOnHand}"/>
Also, where can I modify to add a validation?
The problem is, whenever a user enter a non decimal value, the binding will return 0 instead of null or error
You are slightly incorrect in your above statement. What actually happens when a user enters some text that has an invalid type for a particular field is this:
The invalid text causes a red border (or other decoration depending on the ErrorTemplate value) to appear around the TextBox
The data bound property value remains at the last valid value that was entered
So, in your case, that last valid value may have been 0, which is why you assumed that an invalid value would always return 0. So in fact, only the invalid value is ignored, while the last valid value remains.
However, to improve this issue, you have several options. One way would be to check the value of the Validation.HasError Attached Property before you save the data. Obviously, if you detect that any errors are present, then you would popup a message to alert the user, rather than continuing to save. You can find out more about this method from the Binding Validation.HasError property in MVVM question.
Another option would be to restrict the textual input of a particular TextBox so that it would not be possible to enter non numeric keys. I won't go over the details on how to do this again here, instead preferring to request that you look at the answers to the Numeric Data Entry in WPF question, here on Stack Overflow.
I have a view model property that is set to runtime objects. I want to trigger an animation whenever this property changes, so I was planning to use DataTrigger. However, DataTrigger obviously has the requirement for a Value property--one that I don't know at design-time.
Is there a built in way to trigger an animation whenever a value changes, regardless of what it changes into?
I saw this question but I was wondering if there was anyway to do it purely in XAML. Otherwise I figure I could probably fire an event from my View Model whenever the property changes and listen to that.
One method would be to create a User Control with a dependency property and then bind both of your other properties to that i.e. one at compile time and the other at runtime. Alternatively you could use an Attached Behaviour to do the same thing.
Can add a boolean property and trigger the animation based on the bool property. Whenever the original property changes, set and reset the boolean property so that it triggers the animation and also goes back to default value for next notification.
I have a working OneWay DataBinding from a double CLRProperty to a Texttbox.Text. I don't use a TwoWay because not every userinput is acceptable. BTW I use an existing Command that impements the ICommand interface.
The problem as soon as the user types in a text in the Textbox, the Databinding is destroyed.
<TextBox Text="{Binding Path=myDouble, Converter={converter:DoubleToTextConverter}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>
How should your programm know if the user input is acceptable or not, if you dont tell him?
To check the user input, you could do the following:
Use DataValidation to accept only certain inputs.
Create a second TextBox where the user does the input and if it's ok (you check that in your ViewModel), you apply it to the first TextBox's binded Property myDouble.