How come DataContext property value get inherited by childs but not others? - c#

I am learning wpf and I have a dummy question.
When we set DataContext property of a parent, it gets inherited by its childs which can use the same binding but how come other properties not get inherited?
Yes it make sense that if we set the parent's name (which is a property) to xyz, the child's name doesn't get set to the same which also has the same property but how is it that rule is different for DataContext property?

The value of the DataContext property is inherited because this is explicitly requested by setting FrameworkPropertyMetadataOptions.Inherits on registration of the property.
From the Reference Source:
public static readonly DependencyProperty DataContextProperty =
DependencyProperty.Register(
"DataContext",
typeof(object),
_typeofThis,
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.Inherits,
new PropertyChangedCallback(OnDataContextChanged)));
See also the Dependency Property Information in the Remarks:
Dependency Property Information
Identifier field DataContextProperty
Metadata properties set to true Inherits

Related

PropertyChangedCallback not called

It looks like WPF doesn't always call the registered PropertyChangedCallback procedure of a DependencyProperty. Even if we manually raise PropertyChanged event from the VM, WPF seems to actually evaluate the old and new value of the property before deciding if it would call the callback. So my questions here are:
Why is this so?
What is the workaround?
Details
My ViewModel has a public property define as follows:
Public ReadOnly Property CurrentSelection() As ObservableCollection(Of Object)
My View binds to this property like this (BetterPropertyGrid is a UserControl that wraps a WinForms PropertyGrid in it and has a DependencyProperty named SelectedObjects):
<bd:BetterPropertyGrid SelectedObjects="{Binding CurrentSelection}" />
Now whenever my ViewModel adds or removes objects from CurrentSelection, I manually raise PropertyChanged("CurrentSelection"), but it doesn't seem to update my View.
WPF checks if the property value is actually different from what is was before the change notification was raised. In your case, the same collection instance is returned from the view model property getter, hence the change has no effect.
"Why is this so?": Because old and new property value are equal. In the PropertyChangedEventArgs passed to your PropertyChangedCallback e.OldValue and e.NewValue would reference the same collection instance.
"What is the workaround?": Register a handler for the INotifyCollectionChanged.CollectionChanged event of the SelectedObjects property value, as shown in this answer.

Setting a dependency property of a control in the custom control

I have a infragistics grid that i have inherited from in the my solution . Now i would like to set a dependency property defined in the infragistics grid control in my custom control code behind and not in xaml . How do i accomplish setting the dependency property ?
I was able to set the backing CLR property in my custom control but as expected it didnt trigger off the gridcontrol UI change as expected and hence i m forced to set the dependency property in my custom control .
How exactly do i accomplish this ?
Normally a DependencyProperty is declared like this with CLR property 'wrappers':
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
"Items", typeof(ObservableCollection<string>), typeof(YourControlType));
public ObservableCollection<string> Items
{
get { return (ObservableCollection<string>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
If the Grid that you inherited declared their DependencyProperties like this, then you should be able to use the CLR wrapped properties directly like this:
Items = new ObservableCollection<string>();
Items.Add("Something");
If they didn't do that, then you can see in the wrapped properties how to access them:
anInstanceOfYourControlType.SetValue(ItemsProperty, "some value");
There is of course a chance that they declared internal properties in which case you won't be able to access them, but you should be able to find that out from their online documentation.
You can use DependencyProperty SetValue to set local value of Dependency Property.
dataGridObject.SetValue(DataGrid.ItemsSourceProperty, value);
But in case your DP binded with some CLR property and you want to update it as well, use SetCurrentValue method.
dataGridObject.SetCurrentValue(DataGrid.ItemsSourceProperty, value);

Dependency Property not displaying on initialization

I am not sure if this is even possible, but here is my setup:
I have a customized textbox that is only meant to deal with hotkey selection. In here I have a DependencyProperty that is for the SelectedHotKey.
Then I have a custom control that is a label, the textbox, and a button. This control also exposes a DependencyProperty of the same name as the TextBox, and it merely ties to the TextBox via:
SelectedHotKey="{Binding ElementName=Main, Path=SelectedHotKey, Mode=TwoWay}"
With this dependency property, I am looking to set the textbox's SelectedHotKey, which will change the Text appropriately.
I am then using that user control and binding to my ViewModel.
I have all of this working except for the initialization case.
When my ViewModel is already set up and passed to the UserControl in the binding, that initial setter does not even get hit, so it does not propogate down through my controls. I thought about putting in a PropertyMetaData method, however that is a static method and I do not have access to my instance textboxes.
Any ideas? Let me know if I need to clarify further.
Don't put code logic in the CLR property wrapping the dependency property. As you have already seen, there is no guarantee they will ever be called since the framework can call SetValue directly on the dependency property.
You're in the right track: you have to use the dependency property metadata. Access the instance by using the first parameter of the property changed callback.
DependencyProperty SomeProperty = DependencyProperty.Register(
"Some",
propertyType,
ownerType,
new FrameworkPropertyMetadata(defaultValue, OnSomePropertyChanged));
static void OnSomePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
// "d" is your instance here, cast it to the required type
}

Any way to get event, when some WPF data binding update occurs?

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;
}

What's the framework mechanism behind dependency properties?

I have been reading about dependency properties in several books but all have one thing in common, they just tell us how they are implemented( using static readonly DependencyProperty etc.) but does not tell the exact way they work from inside.
I mean they are implemented as static but still applies to all objects.
Second point of confusion is attached properties.
Is there any tutorial available that can explain all these concepts in an easy way?
My mental model of how dependency properties work:
Any DependencyObject class implements two special properties. One, a static property of the class, is a dictionary of DependencyProperty objects. Every instance of the class can look inside that dictionary to find metainformation about each DependencyProperty - the property's name, its type, any callbacks that have to be called when it's get and set, how it participates in property inheritance, and so on. When you register a dependency property, you're adding an entry to this dictionary.
The other property is an instance property: it's a dictionary, keyed by DependencyProperty, that contains the local value of each DependencyProperty, if it has been set.
The SetValue and GetValue methods that you implement in the setter and getter of the CLR property are basically lazy evaluation on steroids. Instead of storing and retrieving the value of the property in a backing field, they store and retrieve the value of the property in the value dictionary.
The magic of dependency properties is in what GetValue and SetValue actually do.
GetValue looks up the value for the property in the object's value dictionary. If it doesn't find it, it calls GetValue on the parent element, to get what the parent element thinks the value is. For instance, when you create a TextBox in a Window, anything that looks at the TextBox's FontFamily is actually calling GetValue. Unless you've explicitly set the font, there's no entry in its dictionary for that property. So GetValue asks the parent element for the value. The parent element may or may not have FontFamily set; if not, its call to GetValue to returns the value from its parent. And so on, until the Window object is reached and the actual FontFamily value is found.
If you set FontFamily on the TextBox, SetValue stores the value in the value dictionary. The next time anything needs to get the value of the FontFamily for that TextBox, GetValue finds the value in the dictionary and returns it, so it doesn't need to ask the parent element.
If you set FontFamily on the Window, SetValue not only updates the value in Window's value dictionary, it fires off a property-change event that everything dependent on the property hears. (That's why they're called dependency properties, remember.) And if the thing depending on the property is itself a dependency property, it fires off its own property-change events. This is how it is that changing the FontFamily on the Window changes the font for every control in the window and also prompts WPF to re-render the controls that have changed.
Attached properties work using the same kind of approach. Any object that can have attached properties has a dictionary that the attached properties' values are stored in. When you set Grid.Column on a CheckBox in XAML, you're just adding an entry to that CheckBox's dictionary. When the Grid needs to know what column the CheckBox is in, it looks the value up from that dictionary. When you set Grid.IsSharedSizeScope to True on an object, that object's dictionary will contain a new property - a dictionary that contains widths/heights for each SharedSizeKey.
I should emphasize that this is my mental model. I haven't sat down with Reflector and looked at the actual implementation of Register, GetValue, and SetValue to figure out how they actually work. I may be wrong about the details. But it's a model that accurately predicts how this stuff behaves, so it's good enough.
The concept of storing property values in dictionaries is pretty weird to C# programmers. It's old hat to Python programmers, though. In Python, all class properties - all objects, in fact - are stored in dictionaries, and so you can get to their value either through property accessors or just by looking them up. Dependency properties and attached properties are just another way in which .NET, having stolen everything Java had that was worth stealing, is now plundering Python. (Or from wherever Python plundered them from.) Learning Python has made me a much better C# programmer; I recommend it to any C# developer who hasn't done it yet.
Here is a tutorial on dependency properties http://www.wpftutorial.net/DependencyProperties.html that explains a little bit about how they work.
The short explanation of why the DependencyProperty object is in a static field is that it represents the description of the property, not the value of the property. Each DependencyObject has a mapping from DependencyProperty objects to their values.
This is also how attached properties work. Because each DependencyObject is storing a mapping from any DependencyProperty to a value, any type can create a new DependencyProperty and set it on any existing DependencyObject.
just see this post by joshsmith it has some additional informatin in it
http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-dependency-properties-in-wpf/
You can see below a very basic example of dependency property that creates a custom control text box in which space will be not allowed means user can not type space into text box.
1) Create a class with the name of ValidatedTextBox and write the following code in this class file:
public class ValidatedTextBox : TextBox
{
public ValidatedTextBox()
{
}
public static readonly DependencyProperty IsSpaceAllowedProperty =
DependencyProperty.Register("IsSpaceAllowed", typeof(bool), typeof(ValidatedTextBox));
public bool IsSpaceAllowed
{
get { return (bool)base.GetValue(IsSpaceAllowedProperty); }
set { base.SetValue(IsSpaceAllowedProperty, value); }
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (!IsSpaceAllowed && (e.Key == Key.Space))
{
e.Handled = true;
}
}
}
2) Now use the above control into your .XAML file
a) Add namespace of custom control text box like below:
xmlns:CustomControls="clr-namespace: ValidatedTextBox;assembly= ValidatedTextBox "
b) Now, use custom control text box like below:
<CustomControls:ValidatedTextBox IsSpaceAllowed="False" x:Name="MyTextBox" />
It will create a custom control text box that will not allow space. So, Basically Dependency property allows to add feature, extend feature of any control.

Categories