I am trying to set up a custom user control derived from the ToggleButton control.
I would like to set up two new commands, CheckedCommand and UncheckedCommand.
I have defined the commands as below, and am able to bind to them. And I am firing them via some internal events. It all works great.
However I would like to be able to have these commands disable the button as the usual command interface does with CanExecute. As I understand it I need to use the CanExecuteChanged event and set the IsEnabled Property in here. However when am I supposed to bind this event, I looked at using the PropertyChangedCallback event of the DependancyProperty but then how do I unsubscribe the from any previously bound command.
It all ends up looking a bit convoluted, am I missing something simple or is this just the way it is.
[Description("Checked Command"), Category("Common Properties")]
public ICommand CheckedCommand
{
get { return (ICommand)this.GetValue(CheckedCommandProperty); }
set { this.SetValue(CheckedCommandProperty, value); }
}
public static readonly DependencyProperty CheckedCommandProperty = DependencyProperty.Register(
"CheckedCommand", typeof(ICommand), typeof(ToggleTextButton));
I may not understand your specific requirements but in general I wouldn't do it like this. WPF has been primarily designed to be data-driven, whereas here you're implementing event-driven notification. Events are the old-school WinForms way of doing things and they were added mainly to facilitate an easier transition from WinForms to the new data-bound architecture.
IMO a more "correct" solution here would be to expose a boolean dependency property i.e. basically the same thing as the "Checked" property in checkbox. Users of your control can then bind that one property to a boolean property in their view models whose setter will be called whenever the state changes. A second "Enabled" DP will allow both you and your user to control whether or not the control should be enabled, again similar to how it's implemented in Checkbox.
To ask an obvious question though if it's checkbox functionality you're after then why aren't you just templating checkbox? Do you really need a usercontrol for what it is you're trying to achieve?
Related
There is only 3 things inside of INotifyDataErrorInfo:
HasErrors: a read-only boolean property which tells if the object as a whole have any validation errors;
GetErrors: a method which returns validation errors for a given property;
ErrorsChanged: an event which must be raised when new errors – or the lacks of errors – is detected. You have to raise this event for each property.
In the demo project I create a form which display the properties of an object named ‘Person’. Here is how the validation with INotifyDataErrorInfo is enabled in the Binding:
<TextBox Text="{Binding Name,Mode=TwoWay,ValidatesOnNotifyDataErrors=True}"/>
We have to set the ValidatesOnNotifyDataErrors property to true.
The binding will then register itself for the ErrorsChanged event of the binded Person. Eeach time this event is raised for the binded property, the controls will dress itself to display an error. this is done only if the HasErrors is set to true.
Question:
Is there anyone know more detail aobut the ErrorsChanged event is raised for
the binded property, the controls will dress itself to display an
error?
If I binding Address.Country of Person ,will the ErrorsChanged event be raised for the binded property Address.Country or not? why? is there a way make this binding to show Errors too?
<TextBox Text="{Binding Address.Country,Mode=TwoWay,ValidatesOnNotifyDataErrors=True}"/>
I think I can risk an answer, this question is already one year old.
The Binding will register to the ErrorsChanged event in the Class containing the property. In that case, Address must implement INotifyDataErrorInfo.
And, it's you to raise the ErrorsChanged event when you implement the validation logic. Once you have validated the Address.Country, you store the ValidationResults (or simple strings list) and raise the event. The Binding will get the stored ValidationResults list for the PropertyName he is binded to, by calling the method GetErrors(string propertyName)that you wrote yourself implementing the INotifyDataErrorInfo interface.
If this list is not empty, the Binding will set the Property Validation.HasError to True and the control will raise the Validation.Error event. Some controls have a built-in behavior to change their appearance in error case (a TextBox will have a red frame around its border). If you want to show the errors, you have to retrieve them by writing a style in xaml. Plenty of examples out there.
The HasErrors method is used if you want to know if the Person has any errors in its Properties. It's mostly used in such cases : enabling or disabling a save button. Once again, it's you to implement the logic using the HasErrors Property. It's mostly done by binding it to a control Property in xaml.
If I register to be notified of a property's change, it will only notify when the actual property is reassigned. So if I have a property that's a textbox, it won't notify if the text of the textbox changes, right? Is there any way to make it work this way?
If you are interested in specific properties of an object then you should be using a mechanism like INotifyPropertyChanged on the value itself. Unfortunately though in this case TextBox from WinForms doesn't implement INotifyPropertyChanged. In order to listen for changes to its Text property you need to subscribe to the TextChanged event
I have had a hard time imagining why a class would expose a property of type TextBox. Anyhow if you have ended up with such a design, you could simply add two properties, each for the TextBox itself and the text inside and then listen to TextBox's TextChanged event and fire your NotifyPropertyChanged thereupon.
I do feel however that you need to rethink your approach. If your class exposes a property of TextBox type, there should really be places where you actually assign a new TextBox to a class instance and upper layers listening to this change. I don't think that would be the case however. You'd almost certainly be looking for text changes and should therefore expose a property of type string.
I'm still trying to wrap my head around some of the finer points of using WPF and MVVM. One thing that has bugged me for a while is how to get values from the View into the ViewModel. Let me explain the scenario.
I have a Window with several UserControls inside. One of those UserControls has a DependencyProperty of type TimeSpan named CurrentTime. It is bound (in the XAML for the window) to the Window's ViewModel.
Now, I also have a ViewModel for the UserControl. It needs access to the CurrentTime property in order to create objects based off it. How do I get that value into my ViewModel? I see a couple of options:
The simplest is probably just to pass the View into the ViewModel's constructor (or somehow otherwise reference the View from the ViewModel). But that seems so wrong and not WPF/MVVMy.
I could use messaging to actually get the CurrentTime from the other ViewModel. This would certainly work, but seems like overkill.
I could set up a binding in the XAML of the UserControl to bind, OneWayToSource, between the DP and the property in the ViewModel. I can't figure out exactly how to set that up (how do you reference a UserControl's new properties in its own XAML?), but it seems like it could work.
Am I missing any other options? Which of the above (or ones I missed) is the best way to do this?
I read through this thread here on SO, because it was similar, but the answers didn't really answer my question - I would love to do it with bindings or commands or something, but I just can't figure out how exactly.
The third option is the way to go here, but you'll have to specify binding in the code-behind of your UserControl:
public partial class MyUserControl : UserControl
{
public MyUserControl() {
InitializeComponent();
SetBinding(MyPropertyProperty,
new Binding {Path = new PropertyPath("MyViewModelProperty"), Mode = BindingMode.OneWayToSource});
}
}
Any way to get event, when some WPF data binding update occurs?
UPD I'm developing a custom control extending one of standard controls. I need to get notification, when DataContext property of the ancestor control changes, or data binding causes update of any property of the ancestor control.
It sounds like you require: INotifyPropertyChanged to be implemented on your View Model. This obviously depends on your implementation but this is assuming you've followed MVVM.
This then allows you to carry out some work based on the value of a bound property changing (and an event being raised).
As others already mentioned, if your object
implements INotifyPropertyChanged and
the property supports it, register to PropertyChanged and you will be informed about changes.
If you are in a DependencyObject and add your own DependencyProperty, register a DependencyPropertyChangedEventHandler in the metadata to be informed when the property changes-
If you have a DependencyObject and
the property is a DependencyProperty, you can override
OnPropertyChanged. It will be called
every time, a DependencyProperty
value has been changed. You can then filter out the property-changes you are interested in.
If you are outside of a
DependencyObject and want to
listen to a changed value of a DepenendencyProperty, you can use
the DependencyPropertyDescriptor to register for value changes. However take care, using this may produce memory-leaks.
If you're talking about getting a notification from a control perspective (i.e. when a dependency property has been bound to) you can provide a method that will be called passing the value:
public DependencyProperty ItemsSourceProperty = DependencyProperty.Register(
"ItemsSource",
typeof(IList),
typeof(CustomGridControl),
new FrameworkPropertyMetadata(null, OnItemsSourceChanged));
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
e.NewValue;
}
I have ObservableCollection<Foo> that is bound to an ItemsControl (basically displaying a list).
Foo mostly looks like this (there are other members but it doesn't implement any interfaces or events):
class Foo
{
public string Name { get; set; }
//...
}
When the user clicks on an item I open a dialog where the user can edit Foo's properties (bound to a small viewmodel with a Foo property for the selected item), the Xaml looks like this:
<TextBox Text="{Binding Foo.Name,Mode=TwoWay}"
Grid.Column="1" Grid.Row="0" Margin="2" />
The really strange thing is, when the user edits the name, the value in the list changes! (not while typing but after the focus leaves the field)
How does it do that? I haven't implemented the INotifyPropertyChanged interface on the Foo object!
So far I checked that it doesn't just refresh the whole list - only the selected item. But I don't know where I could set a breakpoint to check who's calling.
Update: thanks to casperOne for the link to the solution! I'll add a summary here in case it goes 404:
[..] actually you are encountering a another hidden aspect of WPF, that's it WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.
And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.
This is a total guess, but I'm thinking that because you have two-way binding enabled, WPF is now aware of when it makes changes, and will update other items it knows is bound to the same instance.
So because you have changed the value of the Name property through the textbox, and WPF knows when you have changed that value, it does its best to update whatever else it knows is bound to it.
It uses reflection to set the value of that property. INotifyPropertyChanged is only needed if the TextBox needs to be informed of a change in the Name property of the Foo class.
Because they're databound to the same object. If you change the binding to
{Binding Foo.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
then they'll be in synch when the user types in the textbox.