I have such WPF binding code:
TestModel source = new TestModel();
TestModel target = new TestModel();
Bind(source, target, BindingMode.OneWay);
source.Attribute = "1";
AssertAreEqual(target.Attribute, "1");
target.Attribute = "foo";
source.Attribute = "2";
AssertAreEqual(target.Attribute, "2");
The second assertion fails! This seems odd for me.
Also, I tried 'OneWayToSource' instead of 'OneWay', and all works as expected.
Bind(source, target, BindingMode.OneWayToSource);
target.Attribute = "1";
AssertAreEqual(source.Attribute, "1");
source.Attribute = "foo";
target.Attribute = "2";
AssertAreEqual(source.Attribute, "2");
Other details:
void Bind(TestModel source, TestModel target, BindingMode mode)
{
Binding binding = new Binding();
binding.Source = source;
binding.Path = new PropertyPath(TestModel.AttributeProperty);
binding.Mode = mode;
BindingOperations.SetBinding(target, TestModel.AttributeProperty, binding);
}
class TestModel : DependencyObject
{
public static readonly DependencyProperty AttributeProperty =
DependencyProperty.Register("Attribute", typeof(string), typeof(TestModel), new PropertyMetadata(null));
public string Attribute
{
get { return (string)GetValue(AttributeProperty); }
set { SetValue(AttributeProperty, value); }
}
}
What is wrong with my code?
Setting target.Attribute = "foo"; cleared the binding.
MSDN:
Not only do dynamic resources and
bindings operate at the same
precedence as a local value, they
really are a local value, but with a
value that is deferred. One
consequence of this is that if you
have a dynamic resource or binding in
place for a property value, any local
value that you set subsequently
replaces the dynamic binding or
binding entirely. Even if you call
ClearValue to clear the locally set
value, the dynamic resource or binding
will not be restored. In fact, if you
call ClearValue on a property that has
a dynamic resource or binding in place
(with no "literal" local value), they
are cleared by the ClearValue call
too.
Not a binding expert but I believe you are running into a WPF dependency property precedence issues. It's likely that setting the value directly takes precedence over the binding value. That's why it overrides the binding.
Here's a full dependency property listing: http://msdn.microsoft.com/en-us/library/ms743230.aspx
Example: TextProperty is "Text"
dependency property of TextBox.
Calling these in code should be:
TextBox1.TextProperty="value";
WPF properties can be set two ways:
by invoking DependencyObject.SetValue method (eg. instance.SetValue(TextProperty,"some text"))
or
using CLR Wrapper (eg. instance.Text="some text").
TextBox.TextProperty is a static DependencyProperty object, so you can't assign a string value to a reference type.
If you set Binding Mode to OneWay, this means that the binding works only in one way: the target is updated when the source change.
But the target must be a dependency property, and the code you have is a CLR .NET property. You should set the value on the the target using the registered dependency property name, not just an ordinary .NET property name. The Jared's answer is quite right, this might bring confusion in resolving conflict between WPF dependency property and ordinary .NET CLR property.
If you follow the convention, the dependency property should be in the form of "propertyname"+property.
Example: TextProperty is "Text" dependency property of TextBox. Calling these in code should be:
TextBox1.TextProperty="value";
For more information on setting the source of Binding:
http://msdn.microsoft.com/en-us/library/ms743643.aspx
Related
I'm very new to WPF and while studying (particularly creating a user control), I stumbled upon this thing called "DependencyProperty".
I understand how it works in code but why and when do we need it when I can just create a property and expose it for public use.
Example:
XAML:
<UserControl.....>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="label" Text="Hello"/>
<TextBlock x:Name="text" Text="World!" />
</StackPanel>
</UserControl>
CS file:
public partial SampleUserCtrl : UserControl
{
public string LabelText { get { return this.label.Text; } set { this.label.Text = value; } }
public string TextBoxText { get { return this.text.Text; } set { this.text.Text = value; } }
}
DependecyProperty in WPF has different uses.
Advantages compared to normal .NET property
Reduced memory footprint It's a huge dissipation to store a field for
each property when you think that over 90% of the properties of a UI
control typically stay at its initial values. Dependency properties
solve these problems by only store modified properties in the
instance. The default values are stored once within the dependency
property.
Value inheritance When you access a dependency property the value is
resolved by using a value resolution strategy. If no local value is
set, the dependency property navigates up the logical tree until it
finds a value. When you set the FontSize on the root element it
applies to all textblocks below except you override the value.
Change notification Dependency properties have a built-in change
notification mechanism. By registering a callback in the property
metadata you get notified, when the value of the property has been
changed. This is also used by the databinding.
As you dig deeper to WPF you will also stumble upon DataBinding and object-oriented design patterns like MVVM or MVPVM. Both patterns rely on DataBinding which is achieved through using of Dependency Properties. You cannot perform data binding if it is not a dependency property.
Basically data binding through dependency properties allow the user to update the view when updating a value through code.
Ex: In Windows Forms in order to update a label text you assign its value on the code behind like this:
lbl1.Text = "foo";
In data binding where as you bind in the XAML (View)
<label Text = "{Binding foo}"></label>
and update the values in your code behind:
foo = "foo";
I am not an expert myself so sorry if I might sound confusing.
Dependency property has many benefits over normal property.
A dependency property value can be set by referencing a resource
It can reference a value through data binding
It can be animated. When an animation is
applied and is running, the animated value operates at a higher
precedence than any value (such as a local value) that the property
otherwise has.
You can learn more about it from msdn.
The main advantage of DP property you can find anything in DP like your Control info and you current DataContext info.
public string MyProperty
{
get { return (string)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(string), typeof(MyUserControl), new PropertyMetadata(null, (s, e) => OnChangedValue(s, e)));
private static void OnChangedValue(DependencyObject s, DependencyPropertyChangedEventArgs e)
{
throw new NotImplementedException();
}
I just discovered than I can do the following:
var button = new Button();
button.SetValue(TextBlock.TextProperty, "text");
var text = (string)button.GetValue(TextBlock.TextProperty); // text is "text"
While the above example is a bit unrealistic, it does show that I can attach a regular dependency property onto another object. It doesn't have to be a an attached property (TextBlock.TextProperty is not registerd with DependencyProperty.RegisterAttached().
This bares the questions why are there attached properties in the first place? The only difference I can see for now ist that I can't attach regular dependency properties in XAML. But that's about it. Are there any other differences?
Update:
To make it more clear, the below code works and looks pretty close to an attached property from the end users perspective:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(Button),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
...
button.SetValue(AttachedPropertyDeclarer.TextProperty, "text");
var text = (string)button.GetValue(AttachedPropertyDeclarer.TextProperty);
Compare this to the attached property way:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(AttachedPropertyDeclarer),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
The only effective differnce to an attached property here is that I have to declare the owner of type Button whereas in a attached property it would usually be AttachedPropertyDeclarer. But this only needs to be done if I need a changed event handler (i.e. OnTextChanged).
Regarding your example, you have not as you say, attached a regular dependency property onto another object. All your code has achieved is to store a string value in a Dictionary along with a reference to your object. That does not make it an Attached Property - importantly, you cannot access that string value from the Button directly, as there is no Text property on a Button.
What your code does is actually very similar to this:
Dictionary<object, object> values2 = new Dictionary<object, object>();
var button = new Button();
values2.Add(button, "text");
string text = values2[button].ToString();
Now to answer your question:
The main reason to declare an Attached Property is in order to add a property to a type that you didn't declare, thereby extending its functionality.
A great example of this would be to add a SelectedItems property to the ItemsControl or ListBox class. In doing so, we extend the current, or default functionality of the class. Another good example would be declaring an Attached Property that automatically brings added items into view (again in an ItemsControl or ListBox class).
UPDATE >>>
According to your comments, you seem to be refusing to accept the differences that I have outlined... you said:
There is literally no difference from the end users perspective except that I can't use it in XAML.
Firstly, do you not think that this is a huge difference?.. you won't be able to use it for data binding for a start. Furthermore, you keep saying that you can attach a property to a type that you haven't declared using a DependencyProperty, but you are 100% incorrect. You can reference an Attached Property directly in both code and XAML, while you can't reference what you are calling your attached property directly in either XAML or code.
All you are doing is storing a value in a Dictionary and you certainly don't need the overhead of a DependencyProperty to do that. There really is no comparison between doing that and declaring an Attached Property. From the Attached Properties Overview page on MSDN:
You might create an attached property when there is a reason to have a property setting mechanism available for classes other than the defining class.
Note the following part: a property setting mechanism
Adding values into a Dictionary is not a property setting mechanism. So again, you lose the ability to use your pretend Attached Property in Styles, Animations, Triggers, etc.
To clarify this situation for once and for all, you can develop a simple test project. Implement the IList SelectedItems Attached Property for a ListBox that I mentioned (you can find online tutorials for this) and then do the same using your pretend Attached Property (if it is even possible). The difference in the simplicity of development bewteen the two will clearly show you why you should use an Attached Property instead of a regular DependencyProperty.
If you look closely at dependency property identifier, all DP's are registered with class DependencyProperty and we pass the Owner class type and property name at time of registration.
Sample:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean), typeof(OwnerClass));
At time of registration it creates some unique hash code combining property name and owner class type to represent each DP uniquely.
So, when you set value for that DP on some object like in your case on Button, code flow is like this:
First it will get the unique value generated at time of registration of property and add the key value pair in private dictionary named _effectiveValues declared in class Dependency Object with Key set to unique hashcode at time of registration and value being the value set by user.
Note - No written documentation for this on MSDN but verified this by peeking into source code using reflector.
So, when you set the value from code behind it will work like I mentioned above because it does not validate before adding value in the dictionary if it belongs to that type or not and fetching value will get you the value from dictionary.
Not sure but might be constraint is there in XAML only where WPF guys enforced the type check. Sadly there is no written documentation for this on MSDN.
Attached properties are discovered, when you want to have control over an existing control, but dont want to extend it. A pretty good example is, there is no way to bind BlackOutDates property in XAML for WPF DatePicker. In that case you can use an Attached Property to attach a custom functionality to map the BlackOutDates. This suits good in MVVM, since attached properties provided way for binding in XAML.
public class BlackOutDatesAdapter
{
public static List<DateTime> GetBlackOutDates(DependencyObject obj)
{
return (List<DateTime>)obj.GetValue(BlackOutDatesProperty);
}
public static void SetBlackOutDates(DependencyObject obj, List<DateTime> value)
{
obj.SetValue(BlackOutDatesProperty, value);
}
// Using a DependencyProperty as the backing store for BlackOutDates. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BlackOutDatesProperty =
DependencyProperty.RegisterAttached("BlackOutDates", typeof(List<DateTime>), typeof(BlackOutDatesAdapter), new PropertyMetadata(null, OnBlackOutDatesChanged));
private static void OnBlackOutDatesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as DatePicker;
var list = (List<DateTime>)e.NewValue;
foreach(var date in list)
{
control.BlackoutDates.Add(new CalendarDateRange(date));
}
}
}
Binding in XAML will look like this,
<DatePicker VerticalAlignment="Center"
Width="200"
local:BlackOutDatesAdapter.BlackOutDates="{Binding BlackOutDates}"
DisplayDate="{Binding DisplayDate}" />
In the callback of property, you can do your own mapping of adding the dates to DatePicker. For more information, please read this post.
I'm attempting to bind to a readonly property on a third party control (so no control over the implementation of the property). As I understand, I need to do this as a onewaytosource binding type, and also need to do it in code.
I have the following code to set the binding:
Binding svBinding = new Binding();
svBinding.Path = new PropertyPath("SurfaceScrollViewer");
svBinding.Source = DataContext;
svBinding.Mode = BindingMode.OneWayToSource;
Ds.SetBinding(DiagramSurface.ScrollViewerProperty, svBinding);
And my property implementation on the view model:
public DiagramScrollViewer SurfaceScrollViewer
{
get
{
return surfaceScrollViewer;
}
set
{
surfaceScrollViewer = value;
}
}
private DiagramScrollViewer surfaceScrollViewer;
I can access other properties in the same data context by code, but for some reason, I cannot get this property to bind. Can anyone see where I'm going wrong?
It doesn't work, because it is a bug of wpf. Take a look of this http://meleak.wordpress.com/2011/08/28/onewaytosource-binding-for-readonly-dependency-property/
Hi I misunderstood your question Sorry. It is a kind of bug in wpf for binding ReadOnly properties with OneWayToSource BindingMode you can get exact answer for this is here
I struggle with binding FillProperty in a classe derived from Shape.
public static readonly DependencyProperty NumberNodeProperty = DependencyProperty.Register("Number", typeof(int), typeof(MyDerivedShape), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public MyDerivedShape( DerivedViewModel viewmModel):Shape
{
DataContext = viewmModel;
Binding FillColorBinding = new Binding("FillColor");
SetBinding(FillProperty, FillColorBinding);
Binding numberBinding = new Binding("Number");
SetBinding(NumberNodeProperty, numberBinding);
}
"FillColor" property is declared in a base Viewmodel, from which DerivedViewModel inherits.
"Number" property is declared in DerivedViewModel
FillProperty is the default dependency property in Shape base class.
NumberNodeProperty is a dependency property declared in MyDerivedShape
So , what happens is that when I change "Number" in the DerivedViewModel, change is propagated to the Shape (the Shape draws a number)
But when I change FillColor in the DerivedViewModel, Change is not propagated, and color is not changed . I use FillColor is of type SolidColorBrush.
It seems that the binding does not work... Is it a consequence "Inherits" property set to false for "FillProperty" depedency property ?
I answer myself, because I found the answer :
In fact , in another piece of code in the application , I do something like this :
MyDerivedShape.Fill = Brushed.Red
This has huge consequences,as It destroys the Binding I put in place !
It is connected to "Dependency Property Value Precedence", a topic I was not aware at all.
So, if you bind a ViewModel Property to Dependency Property, you should never then set the Dependency Property directly. If you do so, your binding is lost !
I'm in the midst of testing a user control I've built, and I'm encountering something that's inexplicable to me.
The control's an extension of the ComboBox that handles values of a specific custom type. It has a dependency property of that custom type that is the target property of a Binding.
I've got a trace statement in the setter, and I can see that the property is getting set. But it's not appearing in my user control.
Now, ordinarily I'd say, okay, I've got a bug in my user control. I probably do, though I'm baffled about it. But this question isn't about finding the bug in my control. Read on; here is where it gets weird.
I'm also using Bea Stollnitz's little value converter to help debug the Binding:
public class DebuggingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value; // Add the breakpoint here!!
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException("This method should never be called");
}
}
The idea behind this is that I add this converter to my Binding and can set a breakpoint to see what value is being pushed out to the target. Okay, that works just fine. I can see that the value is being pushed out.
In fact, it works a little too fine. If the DebuggingConverter is attached to the Binding, the user control displays the value. If it's not, it doesn't.
How is that even possible? How could a value converter that does nothing affect the behavior of a bound control?
Edit:
Not that it's likely to help, but here's the XAML for the user control:
<a:CodeLookupBox
Grid.Column="1"
Grid.IsSharedSizeScope="True"
MinWidth="100"
Style="{Binding Style}">
<a:CodeLookupBox.CodeLookupTable>
<Binding Path="Codes" Mode="OneWay"/>
</a:CodeLookupBox.CodeLookupTable>
<a:CodeLookupBox.SelectedCode>
<Binding Path="Value" Mode="TwoWay" ValidatesOnDataErrors="True"/>
</a:CodeLookupBox.SelectedCode>
</a:CodeLookupBox>
Without the converter on the second binding, the control behaves as though I didn't set SelectedCode. Even though a trace statement in the OnSelectedCodePropertyChanged handler shows that e.Value does indeed contain the correct value. This happens irrespective of whether the converter's attached or not.
I've been trying to reverse-engineer this problem with a thought experiment: if you wanted to create a bound user control whose behavior changed if a no-op converter were attached to its binding, how would you do it? I don't know enough about binding to come up with an answer.
Well, the good news is, I know why SelectedCode isn't being set when I'm not using a value converter. The bad news is, I still have something of a mystery, but the problem's been pushed up the food chain a bit, and I have a workaround.
This control is essentially a strongly-typed combo box with a bunch of additional features that are made possible by the fact that it knows what kind of items are in it. The SelectedCode and CodeLookupTable properties are strongly typed, and they hide the underlying SelectedItem and ItemsSource properties, which aren't. (This, by the way, is why this is a user control and not a subclass of ComboBox; I don't want those properties to be visible because a lot of things can happen if they get set improperly, none of them good.)
Here's what's happening. This is my debugging output when the value converter is attached (the number is the hash code of the control, because I've got a bunch of them that all get drawn simultaneously when the program's initialized):
14626603: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
14626603: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
This is the expected behavior. The CodeLookupTable property is set, so setting SelectedCode to one of the items in that collection correctly sets SelectedItem on the underlying ComboBox.
But without the value converter, we get this:
16143157: OnSelectedCodePropertyChanged:
SelectedCode property set to Unlicensed Driver [VC12500(A)]
box.MainComboBox.ItemsSource =
16143157: OnCodeLookupTablePropertyChanged
CodeLookupTable property set to Proceedings.Model.CodeLookupTable
box.MainComboBox.ItemsSource = MS.Internal.Data.EnumerableCollectionView
Here, the SelectedCode property is being set before the CodeLookupTable property is. So when the method tries to set SelectedItem on the underlying ComboBox, nothing happens, because the ItemsSource is null.
And here is the root of the problem. I've foolishly assumed that the order that bindings update their target in is the same as the order they're declared in the XAML. (One of the reasons I've expressed the bindings as elements instead of attributes is because the order of elements in an XML document is deterministic and the order of attributes isn't. It's not like I didn't think about this.) This is apparently not the case.
I've also assumed, maybe a little less foolishly, that the order in which bindings update their target isn't dependent on whether or not they have attached value converters. Well, it is. I wonder what else it depends on.
Mercifully, I have a way to work around this. Since my CodeLookup object contains a reference to the CodeLookupTable, I can make the SelectedCode setter set the CodeLookupTable (and thus the ItemsSource) property first, if it hasn't already been set. That'll make this problem go away without having to stick a fake value converter on the binding and hope that the way bindings behave never changes.
Edit
Here's what the property declarations look like:
#region SelectedCode
public static readonly DependencyProperty SelectedCodeProperty = DependencyProperty.Register(
"SelectedCode", typeof(CodeLookup), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnSelectedCodePropertyChanged));
private static void OnSelectedCodePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookup code = e.NewValue as CodeLookup;
// this right here is the fix to the original problem:
if (box.CodeLookupTable == null && code != null)
{
box.CodeLookupTable = code.Table;
}
box.MainComboBox.SelectedItem = e.NewValue;
}
public CodeLookup SelectedCode
{
get { return GetValue(SelectedCodeProperty) as CodeLookup; }
set { SetValue(SelectedCodeProperty, value); }
}
#endregion
#region CodeLookupTable
public static readonly DependencyProperty CodeLookupTableProperty = DependencyProperty.Register(
"CodeLookupTable", typeof(CodeLookupTable), typeof(CodeLookupBox),
new FrameworkPropertyMetadata(OnCodeLookupTablePropertyChanged));
private static void OnCodeLookupTablePropertyChanged(DependencyObject source,
DependencyPropertyChangedEventArgs e)
{
CodeLookupBox box = (CodeLookupBox)source;
CodeLookupTable table = (CodeLookupTable)e.NewValue;
box.ViewSource = new CollectionViewSource { Source = table.Codes };
box.View = box.ViewSource.View;
box.MainComboBox.ItemsSource = box.View;
}
public CodeLookupTable CodeLookupTable
{
get { return GetValue(CodeLookupTableProperty) as CodeLookupTable; }
set { SetValue(CodeLookupTableProperty, value); }
}
#endregion
try to implement the ConvertBack function too, you are using two-way binding so the problem may be that the exception will be ignored by the "xaml" but when you step in debug mode you maybe stop the "send value back"-operation?
Hmm...very strange. I've seen similar behavior when dealing with MultiBindings with multiple converters, but not on a simple binding. Out of curiosity, how are you defining your DPs on the control? (including the callbacks, metadata options, etc)
Some stuff to try (after removing the converter hook):
Default the mode (ie, remove the TwoWay)
Remove the ValidatesOnDataErrors
Add an AffectsRender to the SelectedCode DP
What does setting SelectedCode do? Can you post the code for the property changed handler?
You've suggested that debugging shows the property is being set to the correct value, so the most obvious suggestion is that the code providing your intended behaviour is incorrect.