I would like to hide a control such as a TextBox when it has a binding on a property such as the Text property that is invalid (has thrown a BindingExpression path error). This is different from simply checking to see if the binding's value is null in a trigger. Null may in fact be a perfectly acceptable value, and the control should still be displayed. Basically I have a DataTemplate that I want to reuse with several different types of objects from my VM, some of which may have certain properties in common, and some of them may have unique properties. When a particular property does not exist on the object that is currently the binding source of the DataTemplate, the DataTemplate will have some sort of additional trigger or binding that will hide the particular control that is bound to the property that does not exist.
You could play around with the Validation.ErrorTemplate to style the control when a validation error occurs.
Then just set the ValidatesOnDataError = True in the binding and away you go
Related
Before I start to explain my problem: The Slider is just an example for the following problem. I work on a custom control, that has to do a very similar thing like the slider does here:
Scenario:
I have bound a Slider.Value to my ViewModel property called MyValue.
I have defined the Maximum of the Slider to be 100.
Now I set the Property MyValue to 200.
What is the problem?
The Slider will internally coerce the value to be 100.
But the property MyProperty isn't being updated.
In my case (the custom control I built), I need to continue with the coersed value (100) later on, NOT the old (200) value.
Question:
Is there anything I can do in my custom control?
For example I tried myControl.GetExpression(MyValueProperty).UpdateSource(); in both my CoerseValueCallback and PropertyChangedCallback, but no matter what I try, the setter of the bound ViewModel-property is NEVER called and the property stays out of sync.
Bind the Maximum property of your Slider to another view model property and implement logic to ensure that your values are always within the valid range in your view model class.
The control rightfully coerces the values but the logic of synchronizing them should be implemented in the view model class.
Your custom control should be able to simply set the source property of its current DataContext whenever the value is coerced though.
this.GetBindingExpression(Slider.ValueProperty).ResolvedSourcePropertyName should give you the name of the source property and then you can for example set it using reflection if calling UpdateSource() on the BindingExpression doesn't work.
I have a ListBox bound to an ObservableCollection of type T - each ListBoxItem is a checkbox with IsChecked bound to a bool property in T. I want to validate the checked items in the ListBox so that at least one checkbox must be ticked - if none of the check boxes are ticked I want to show a red border (standard validation notification) around the ListBox.
How do I go about doing that? Can I use ValidatesOnDataErrors?
Implement IDataErrorInfo in the class that exposes the ObservableCollection<T> property and make the indexer return an error for that property's name if all of the objects in the collection have a value of false in their boolean property. Then use the DataErrorValidationRule in your binding's ValidationRules.
Your goal is to validate selected items of a ListBox: at least one selected item is required. First, there are different ways to handle the selection itself:
a) You can use the ListBox selection mechanism via ListBox.SelectedItem.
I guess, you can specifiy the binding as SelectedItem="{Binding SelectedThing, ValidatesOnNotifyDataErrors=True}" and WPF's regular validation works. Not sure, if this works well with multi-selection.
b) You can use ListBox.SelectedItems. Binding is not possible and needs to be faked via code behind event handler. Thus, WPF's validation cannot trigger here.
c) You use your own IsSelected property (or similar) per item, either explicitely bound to your viewmodel via CheckBox or implicitely via ListBoxItem.IsSelected (via ListBox.ItemContainerStyle).
From here you could create a bool IsValidSelection property in your viewmodel that updates whenever the selection changed. Or you can run validation rules on any of the resulting properties of your viewmodel (e.g. SelectedItems). However, you don't validate the bound ListBox.ItemSource itself! Therefore WPF's standard mechanisms don't work (the list box doesn't get a red border or whatever).
Workarounds
You can explicitely create error notifications by showing an otherwise invisible Label and binding its visibility to the above-mentioned bool IsValidSelection property. This is a very explicit way, not using WPF validation at all.
You can modify your INotifyDataErrorInfo (or similar) implementation to trigger errors on a different property name. This is not possible, if you use a generic ValidatableViewModel<T> (like me). I guess this was the intention of the other answer.
I do not understand the various data binding modes in WPF, such as:
One-Way
Two-Way
One-Time
etc...
What does each of these modes mean?
When should they be used?
OneWay: Use this when you want the bound property to update the user interface.
TwoWay: This has the same behavior as OneWay and OneWayToSource combined. The bound property will update the user interface, and changes in the user interface will update the bound property (You would use this with a TextBox or a Checkbox, for example.)
OneTime: This has the same behavior as OneWay, except it will only update the user interface one time. This should be your default choice for binding (for various reasons I won't elaborate on here). You should only use other types of bindings if you actually need the extra functionality.
OneWayToSource: This is the opposite of OneWay -- user interface value changes update the bound property.
If you don't specify anything, then the behavior will depend on the control that you are using.
For more info, see BindingMode enum on Microsoft Docs.
A binding consists of two entities:
The Source (Typically the ViewModel in MVVM scenarios)
The Target (The UI control)
The target has to be a DependencyObject (for binding to work) and the source can be either a DependencyObject or it should have some mechanism to imitate the WPF Binding system about it being changed (Implemeting INotifyPropetyChnaged interface).
MVVM recommends the ViewModel project to be free from any View related references and hence it is recommended to use INotifyPropertyChanged interface to make the Source object being heard by WPF binding.
Binding happens between a property of Source and a property of Target (has to be a DependencyProperty).
e.g. The TextPropertyof the TextBox class is DataBound to (say) UserName property of the view model.
WPF binding offers four types of Binding. Remember, Binding runs on UI thread unless otherwise you specify it to run otherwise.
OneWay: The target property will listen to the source property being changed and will update itself. If you programmatically change the ViewwModel's UserName property, it will reflect in the text box. This is of intermediate cost as the binding system watches only Source for changes.
TwoWay: The target property will listen to the source property being changed and will update itself. AND The source property will listen to the target property being changed and will update itself. Both the TextProperty and the UserName property will remain in sync and will update each other if one changes. This is most costly as the binding system has to watch both sides for change.
OneWayToSource: The Source property will change if the target property is changed. If the user changes the TextProperty, the UserName property will take up the changed value. This again is of intermediate cost as the binding system watches only Target for changes.
OneTime: This happens only once during the lifetime of Binding, the Target property will be updated with the Source property when the Binding happens. This is least costly and is advisable for scenarios where you have static data to be shown e.g. Label, TextBlock etc.
If you don't mention anything, every target property has a default binding mode associated with itself. E.g. the TextProperty of a TextBox has default binding mode as TwoWay. For the TextProperty of a TextBlock it is one way.
It is advisable that you choose the right mode as it can help you reduce the application latency especially in cases where you have large number of controls in your UI.
For more on MVVM here is an article written by me.
I have a an object which is set to the DataContext in a Window. I have textboxes in the window which are bound to the properties on the object. There seems to be a delay however before the properties on the object are updated.
<TextBox x:Name="txtPropertyOne" Text="{Binding Path=PropertyOne,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
If I change the values in a few textboxes then quickly try to access the properties to which they map, sometimes there are changes which aren't reflected in the properties of the object. I thought that was what the PropertyChanged UpdateSourceTrigger was supposed to take care of.
If I change the values in a few
textboxes then quickly try to access
the properties to which they map
I can interpret this statement in two ways:
You're trying to access the values on a background thread. In that case, you may be accessing the properties before the UI thread has had a chance to do its thing.
You're using a separate message on the UI thread to check the values. Bindings are updated at a priority lower than Send and Normal. So if your message is priority Send or Normal it will be processed before any pending binding updates.
If this doesn't answer your question, please clarify what you mean by "quickly trying to access the properties".
The basic rule of WPF Databinding is simple:
The target property must be a
dependency property, and you're
already correct, it's bound to Text
property of TextBox.
The source property can be a CLR
object (other than any derived WPF's
DependencyObject), but the object
must employ or implement its own
INotifyPropertyChanged.
Have you you already implemented INotifyPropertyChanged on your object?
I am deriving from combobox (WinForms) and am providing a new implementation for the Selectedvalue property.
It works fine as is, but any change to the selectedvalue property is not updating other controls bound to the same "binding context" to change their values accordingly.
I did try adding the BindableAttribute(true) to the property, but still it does nottrigger the change in value to the other linked controls.
The control's DataBindings.add(...) is all set up. And other controls are also bound to the same data filed on the same datasource.
Any ideas what i am doing wrong.
Have you called your base class' implementation of overridden methods? It's possible that failing to call the base class implementation is accidentally circumventing the code that fires various event plumbing.