As a newbie in Data-Binding, I don't know what I am doing wrong.
I have some GUI elements defined in XAML, and I have data-binded them with appropriate ViewModels. So far so good.
I also have some custom elements (geometrical shapes) that I place inside a Canvas (which Canvas I place inside the mainwindow through a user-control). I derived these entities from FrameworkElement, to have support for data-binding.
So what I have done is to register some DependencyProperties and set the bindings to one of the existing ViewModels, as it seemed to me logical.
Now the DependencyProperties of these custom classes, display some strange behaviour.
i) When I keep the focus only on the Views (controls) that use the same ViewModel with the custom elements, the properties update normally. If I click everywhere else, the bindings break.
ii) Sometimes, the Callback wasn't called although the property was changing.
iii) When the StartupURI in App.xaml was the MainWindow, if I declared the ProfileV as a field (no matter where it was instantiated), the databinding mechanism worked in the way of (i). If it was declared inside the constructor, the mechanism didn't worked.
What I am doing wrong, and what crucial thing i misunderstand about databinding ??
class ProfileV : FrameworkElement, IGraphicalElement
{
public int SelectedTab
{
get { return (int)GetValue(SelectedTabProperty); }
set { SetValue(SelectedTabProperty, value); }
}
public static readonly DependencyProperty SelectedTabProperty =
DependencyProperty.Register("SelectedTab", typeof(int), typeof(ProfileV),
new PropertyMetadata(new PropertyChangedCallback(CallBack)));
public ProfileV(GeneralExecutionVM VM,CanvasV canvasV)
{
DataContext = VM;
BindingOperations.SetBinding(this, SelectedTabProperty, new Binding("SelectedTab"));
}
public static void CallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
}
Which binds with this
public class GeneralExecutionVM : ObservableObject
{
private int _SelectedTab;
public int SelectedTab
{
get { return _SelectedTab; }
set
{
if (_SelectedTab == value) return;
_SelectedTab = value;
base.RaisePropertyChanged("SelectedTab");
}
}
}
(Observable Object, is the base class from the MVVM Foundation, of Josh Smith.)
ANSWERED
OK i found it. The misconception here is about the DataContext.
Be careful when and where you set it, against setting an explicit source object. I misused it here, and caused a small chaotic situation.
Related
Has anyone ever heard of implementing IDependencyObject instead of inheriting from it -- that way one could actually create a class hierarchy instead of having to use only interfaces when trying to get both dependency object/property and custom behavior on our classes.
I want to have a hierarchy of class kinds that are directly usable in the context of an existing structure, i.e. Polygon. I want to be able to use my PolyType in any place, and without any more dialogue and indirection that would be required if I place the PolyGon existing type as a Part of my DependencyObject. But I also want to be able to have my class as the a) the target of {Binding} markup extension, b) Animate properties of PolyType and c) apply themed styling to PolyType.
I want to implement IDependencyObject instead of being forced to inherit from it directly, and obstructing my ability to be a direct descendent and usable in place of, PolyGon.
Not sure why you have to inherit from DependencyObject. I use a custom code snippet that generates the following code to register a dependancy property:
public partial class UserControl1 : UserControl
{
public static DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(Polygon), typeof(UserControl1), new FrameworkPropertyMetadata(new PropertyChangedCallback(MyProperty_Changed)));
public Polygon MyProperty
{
get { return (Polygon)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
private static void MyProperty_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
UserControl1 thisClass = (UserControl1)o;
thisClass.SetMyProperty();
}
private void SetMyProperty()
{
//Put Instance MyProperty Property Changed code here
}
public UserControl1()
{
InitializeComponent();
}
}
As you can see the DependencyObject can be any type of object. If this is not what you need, please post you code examples, or explain your situation better.
If I create a custom control like this:
public class MyControl : ContentControl
{
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register(
"Items",
typeof(ObservableCollection<object>),
typeof(MyControl),
new PropertyMetadata(null));
public MyControl()
{
// Setup a default value to empty collection
// so users of MyControl can call MyControl.Items.Add()
Items = new ObservableCollection<object>();
}
public ObservableCollection<object> Items
{
get { return (ObservableCollection<object>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
}
And then allow the user to bind to it in Xaml like this:
<DataTemplate>
<MyControl Items="{Binding ItemsOnViewModel}"/>
</DataTemplate>
Then the binding never works! This is due to the Dependency Property Precedence, which puts CLR Set values above Template bindings!
So, I understand why this isn't working, but I wonder if there is a solution. Is it possible to provide a default value of ItemsProperty to new ObservableCollection for lazy consumers of MyControl that just want to add Items programmatically, while allowing MVVM power-users of My Control to bind to the same property via a DataTemplate?
This is for Silverlight & WPF. DynamicResource setter in a style seemed like a solution but that won't work for Silverlight :(
Update:
I can confirm SetCurrentValue(ItemsProperty, new ObservableCollection<object>()); does exactly what I want - in WPF. It writes the default value, but it can be overridden by template-bindings. Can anyone suggest a Silverlight equivalent? Easier said than done! :s
Another Update:
Apparently you can simulate SetCurrentValue in .NET3.5 using value coercion, and you can simulate value coercion in Silverlight using these techniques. Perhaps there is a (long-winded) workaround here.
SetCurrentValue workaround for .NET3.5 using Value Coercion
Value Coercion workaround for Silverlight
Can't you just specify the default property of the dependency property:
public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
"Items",
typeof(ObservableCollection<object>),
typeof(CaseDetailControl),
new PropertyMetadata(new ObservableCollection<object>()));
or am I missing what you are after?
Edit:
ah... in that case how about checking for null on the getter?:
public ObservableCollection<object> Items
{
get
{
if ((ObservableCollection<object>)GetValue(ItemsProperty) == null)
{
this.SetValue(ItemsProperty, new ObservableCollection<object>());
}
return (ObservableCollection<object>)GetValue(ItemsProperty);
}
set
{
this.SetValue(ItemsProperty, value);
}
}
When ObservableCollection properties misbehave, I try throwing out assignments to that property. I find that the references don't translate right and bindings get lost, somehow. As a result, I avoid actually setting ObservableCollection properties (preferring, instead, to clear the existing property and add elements to it). This becomes really sloppy with a DependencyProperty because you're going to call your getter multiple times in your setter. You might want to consider using INotifyPropertyChanged instead. Anyway, here's what it'd look like:
EDIT: Blatantly stole the getter from SteveL's answer. I reworked it a touch so that you only have a single call to GetValue, is all. Good work around.
public ObservableCollection<object> Items
{
get
{
ObservableCollection<object> coll = (ObservableCollection<object>)GetValue(ItemsProperty);
if (coll == null)
{
coll = new ObservableCollection<object>();
this.SetValue(ItemsProperty, coll);
}
return coll;
}
set
{
ObservableCollection<object> coll = Items;
coll.Clear();
foreach(var item in value)
coll.Add(item);
}
}
Note that this is depending on your default to set correctly. That means changing the static ItemsProperty default to be a new ObservableCollection of the correct type (i.e. new PropertyMetadata(new ObservableCollection()). You'll also have to remove that setter in the constructor. And note, I've no idea if that'll actually work. If not, you'll want to move to using INotifyPropertyChanged for sure...
In my .NET 4.0 project I've got an object that has public fields and this object neither implements INotifyPropertyChanged nor inherits DependencyObject, and it will never do. However, I need a mechanism to "bind" to fields of this object in my WPF control. I know I can't do it directly as binding requires a dependency property (or at least, properties and notifying property changes), so what can I do to implement the binding functionality I need. I've tried something like this in my WPF control:
void FirePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public float Friction
{
get
{
if (CurrentObject != null)
{
return CurrentObject.Friction;
}
else
{
return 0.0f;
}
}
set
{
if (CurrentObject != null)
{
CurrentObject.Friction = value;
FirePropertyChanged("Friction");
}
}
}
public PlatformObjectTemplate CurrentObject
{
get
{
return GetValue(CurrentObjectProperty) as PlatformObjectTemplate;
}
set
{
SetValue(CurrentObjectProperty, value);
FirePropertyChanged("Friction");
FirePropertyChanged("CurrentObject");
BindShapes();
IntersectionComboBox.SelectedItem = CurrentObject.IntersectionStaticMethod;
}
}
public static readonly DependencyProperty CurrentObjectProperty = DependencyProperty.Register("CurrentObject", typeof(PlatformObjectTemplate), typeof(PlatformStaticObjectPropertyEditor), new PropertyMetadata(null));
My WPF control implements INotifyPropertyChanged, and my PlatformObjectTemplate does not have properties, just public fields like Friction. I need to bind to my object in XAML as such:
(in my control): //DoubleUpDown is from the WPF toolkit.
<tk:DoubleUpDown Margin="91,10,7,0" Name="doubleUpDown1" VerticalAlignment="Top" Value="{Binding Friction, ElementName=window, FallbackValue=0}" />
(in my main window):
<my:PlatformStaticObjectPropertyEditor x:Name="platformStaticObjectPropertyEditor1" CurrentObject="{Binding CurrentObject, ElementName=window}" />
I put a breakpoint in the getter of Friction property, and it tries to bind before the CurrentObject is bound, and because it is null, I can't read the correct friction value from the object. I've tried to fire Friction property changed in the setter of the CurrentObject, to populate the Friction when CurrentObject gets set, but that doesn't work either.
Ok, here are two requirements:
PlatformObjectTemplate will not use properties. It will have public fields.
I need a declarative way of binding as usual, just as I used in the XAML above.
I probably have got things over-complicated, and I must be missing some stuff. What is the most "correct" and "declarative" way of doing this right, within the constraints of my requirements just above?
Thanks,
Can.
object neither implements INotifyPropertyChanged nor inherits DependencyObject, and it will never. However, I need a mechanism to "bind" to fields of this object in my WPF control
poyra, I have this same situation. Because one cannot bind to instance fields, your best option is to create wrapper classes which implement INotifyPropertyChanged.
Do folks have any guidance on when a simple .NET property that fires INotifyPropertyChanged.PropertyChanged is sufficient in a view model? Then when do you want to move up to a full blown dependency property? Or are the DPs intended primarily for views?
There are a few approaches:
1. The dependency property
While you using the dependency property it makes the most sense in elements-classes that have a visual appearance (UIElements).
Pros:
WPF do the logic stuff for you
Some mechanism like animation use only dependency property
'Fits' ViewModel style
Cons:
You need to derive form DependencyObject
A bit awkward for simple stuff
Sample:
public static class StoryBoardHelper
{
public static DependencyObject GetTarget(Timeline timeline)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
return timeline.GetValue(TargetProperty) as DependencyObject;
}
public static void SetTarget(Timeline timeline, DependencyObject value)
{
if (timeline == null)
throw new ArgumentNullException("timeline");
timeline.SetValue(TargetProperty, value);
}
public static readonly DependencyProperty TargetProperty =
DependencyProperty.RegisterAttached(
"Target",
typeof(DependencyObject),
typeof(Timeline),
new PropertyMetadata(null, OnTargetPropertyChanged));
private static void OnTargetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Storyboard.SetTarget(d as Timeline, e.NewValue as DependencyObject);
}
}
2. The System.ComponentModel.INotifyPropertyChanged
Usually, when creating a data object, you’ll use this approach. It is simple and neat solution for Data-like stuff.
Pros and Cons - complementary to 1. You need to to implement only one event (PropertyChanged).
Sample:
public class Student : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
private string name;
public string Name;
{
get { return name; }
set {
name = value;
OnPropertyChanged(new PropertyChangedEventArgs("Name"));
}
}
3.PropertyNameChanged
Rising an event for each property with specified name(f.e. NameChanged). Event must have this name and it is up to you to handle/rise them. Similar approach as 2.
4. Get the binding
Using the FrameworkElement.GetBindingExpression() you can get the BindingExpression object
and call BindingExpression.UpdateTarget() to refresh.
First and second are the most likely depending what is your goal.
All in all, it is Visual vs Data.
As far as I know, DependencyProperty is only required when you need
PropertyValue inheritence
you need to allow the property to be set in Style setters
Use animation for the property
etc.
These features will not be available with normal properties.
DependencyProperty is required if you want to allow a binding to be set on the property. Usually this is for custom UIElements you create. You want to allow people to be able to bind data to your UIElements.
<local:MyUIElement MyProperty={Binding Path=SomethingToBindTo} />
To do this requires that MyProperty is a dependancy property
The main problem I see with INotifyPropertyChanged is if you viewmodel is complex containing many nested types it appears that you have to bubble the PropertyChanged event up through the hierarchy.
As the other answers have already said enough about when to create dependency property. i.e.
PropertyValue inheritence
you need to use binding on a property
Use animation for the property
The one more perspective/question on this is "In a WPF application is makes sense to create dependency properties in a control cause they are likely to change during user interaction like Height,width, text,content, background etc but what about other classes like Behaviors Classes(Non UI classes). Do properties in those classes need to be a dependency property?"
I won't say for very absolute or emphasis on some set of rules here but you should create your properties as DP. As from design perspective if a property is DP it's always in default form of WPF to use/bind.i.e.
As a DP is much more fast/natural in reflecting changes compare to a normal CLR property.
A DP has validation mechanism to validate the value assigned and a default structure to revert the value.
A DP has Coerce value callback to control the limits of property.
A DP has meta data associated with it unlike CLR property.
In terms of practices I've seen people doing many mistakes in nested bindings and then raising changes these kind of faults doesn't happen with a DP cause of it's design and compatibility of raising change itself. So with a little extra syntax you put a flexibility/performance/ easeness to your application. So go for it wherever affordable.
Still can't say sure for ViewModel classes/other helper classes. will update the answer if found convincing reasons in future.
Just a post worth reading on this topic
I'm not quite sure if I've got the right grasp on this or not, what I've read seems to agree with what I'm trying to do, however It doesn't seem to be working.
If I add an additional owner to a dependency property of a class, whenever the orig class dp changes, the change should get propagated to the additional owner, correct?
What I have is a custom control, which I want to set a property on, and then on certain objects that are within the custom control data template inherit this property value.
public class Class1: DependencyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders {
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
static Class1(){
LongDayHeadersProperty = DependencyProperty.Register("LongDayHeaders", typeof(bool), typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
}
}
public class Class2: DependecyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
static Class2(){
LongDayHeadersProperty = Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
}
}
But if I assign a DependencyPropertyDescriptor to both properties, it only fires for the Class1 and Class2 doesn't change.
Have I missed something in my understanding?
UPDATE
After some testing, I'm not even sure if my child control is considered a child control within the logical or visual tree. I think it is, but the lack of success leads me to believe otherwise.
There a many class2's which exist in an observable collection of class1. This, to me, makes them childs of class1? But even if I use RegisterAttach on class2, and set the property in class1, it doesn't seem to have any effect?
As MSDN states, the Inherits flag only works when you use RegisterAttached to create the property. You can still use the property syntax for the property.
Update
For clarity, here is how I would define the properties:
public class Class1 : FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
DependencyProperty.RegisterAttached("LongDayHeaders",
typeof(bool),
typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
public bool LongDayHeaders
{
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
}
public class Class2: FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
public bool LongDayHeaders
{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
}
If you want your children to be logical children of your control, you need to call the AddLogicalChild. Also, you should expose them through the LogicalChildren property. I must also point out that both classes must derive from FrameworkElement or FrameworkContentElement, as the logical tree is only defined for these elements.
Since you are using an ObservableCollection, you would handle the collection changed events and Add/Remove the children depending on the change. Also, the LogicalChildren property can just return your collection's enumerator.
You are confusing DependencyProperties with Attached (Dependency) Properties.
A DP is for when a class wants bindable, stylable etc properties on itself. Just like .NET properties, they are scoped within their classes. You can register for a property changed event on individual objects, but not globally. TextBox.Text is an example of this. Note that Label.Text is unrelated to TextBox.Text.
An AP is for when a class wants to decorate another object with additional properties. The class that declares the AP is able to listen for property changed events on ALL instances of other objects that have this AP set. Canvas.Left is an example of this. Note that you always have to qualify this setter: <Label Text="Hi" Canvas.Left="50"/>