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 !
Related
I have a dependency property on a class inheriting from adorner, like so:
public class LoadingAdorner : Adorner
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof (string), typeof (LoadingAdorner), new PropertyMetadata(default(string)));
public string Text
{
get { return (string) GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty IsShowingProperty = DependencyProperty.Register("IsShowing", typeof (bool), typeof (LoadingAdorner), new PropertyMetadata(default(bool)));
...
}
Adorner's don't really have any XAML, but I wanted the text of this adorner to be bindable to the viewmodel. So I create the binding in code, in the view's constructor, like so:
private readonly LoadingAdorner _loading;
public MainWindow()
{
InitializeComponent();
_loading = new LoadingAdorner(MainPage);
var bind = new Binding("LoadingText"){Source = DataContext};
_loading.SetBinding(LoadingAdorner.TextProperty, bind);
}
The DataContext is my view model, my view model implements INotifyPropertyChanged, LoadingText is a string property that calls OnPropertyChanged, etc. All bindings in XAML work fine, however, the code binding does not.
I believe it is because at the time of creating the binding, the view model has not yet been set to the DataContext (it is null), I do this on the line after creating the view. If I set this binding to a property on my view using Source = this, it works.
My question is, why are the XAML bindings are capable of reacting to the source object changing, while the code binding doesn't appear to be? Is there a proper way for me to create a binding that will react to this similiar to the XAML bindings?
Binding do not and cannot react to source changes, it is a logical impossibility, objects do not change properties and references to objects change. Bindings can react to DataContext property changes but only if you do not do something horrible like Source = DataContext which kills the mechanism by getting the current data context once only. Just drop that so the DataContext is the default source again and the binding should react to the changes.
If the DataContext is on another object than the one that is bound it needs to be moved into the Path, i.e. new Binding("DataContext.LoadingText"){ Source = this }.
I've bound the visibility of some buttons to a bool, but when the bool changes, the button's visibility does not change. Why could this be?
The boolean is set up as such:
public static readonly DependencyProperty editModeToggle = DependencyProperty.Register("editMode", typeof(bool), typeof(Window));
public bool EditMode
{
get { return(bool)GetValue(editModeToggle); }
set { SetValue(editModeToggle, value); }
}
I'm pretty sure the binding isn't at fault.
[Note: I have set up a Converter that works and the binding works. The visibility just doesn't change when I change from true to false or vice versa]
Binding:
<Button Content="Test" Visibility="{Binding ElementName=mainWindow, Path=EditMode, Converter={StaticResource BooltoVisibilityConverter}/>
There are a few things you need to check when a binding does not work as expected:
Does the bool property notify change using
INotifyPropertyChanged?
Do you use a converter to convert from
bool to Visibility?
Do you see any binding errors in output
window?
Have you tried putting a breakpoint on binding in xaml
or setter in bool property?
As you have mentioned in your comment, you have not implemented INotifyPropertyChanged interface.
The need to implement the interface is whenever value of the property in ViewModel changes, there has be be a way for binding to know that. So, after implementing INotifyPropertyChanged, for each property, you raise the PropertyChanged event with the property name in it. That way, the binding knows that value of the property has changed.
There are lots of articles online. Here is one to get you started: INotifyPropertyChanged and WPF
Dependency Property registration is not correct -
public static readonly DependencyProperty editModeToggle =
DependencyProperty.Register("editMode", typeof(bool), typeof(Window));
It should be-
public static readonly DependencyProperty editModeToggle =
DependencyProperty.Register("EditMode", typeof(bool), typeof(Window));
Notice the spelling of property - 'E' should be capital since its case sensitive and your property name is EditMode not editMode.
In this case you don't need point 1 from decyclone list since you are using a dependency property. I think that you should add Mode=TwoWay in binding if you don't have it, that will solve it.
I am working in silverlight.
Made a new UserControl called TextBoxWithButton.
Now i want add a new property to my new control called TextBoxBackground.
I did this :
public partial class TextBoxWithButton : UserControl
{
public Brush TextBoxBackground
{
get{return textBox.Background;}
set{textBox.Background = value;}
}
}
This works fine, but when I try to animate this property I get an exception.
I think it's because TextBoxWithButton should be defined as a dependency property but I don't know exactly how to to this.
You need to turn this into a Dependency Property. For details on implementing a DP, see Custom Dependency Properties.
Once you have this setup as a Dependency Property, just bind your (inner) TextBox.Background to the "local" TextBoxBackground property (in xaml). You can then animate the UserControl's TextBoxBackground property as needed, and the "inner" property will change as well.
I want a 1-time databind between a checkbox (IsChecked propety) in a childWindow and a nested member variable in it's DataContext object, such that only the initial IsChecked property is set by the member variable. The member variable (binding source) is not INotifyPropertyChanged or marked as a DependencyProperty- but I think that is ok b/c I only want it to be evaluated once- when it gets its initial value.
Binding (in testChildWindow.xaml):
<CheckBox Content="Show Username?" Name="cbShowUser" IsChecked="{Binding Path=User.showUser}"/>
Setting DataContext (in parent window code-behind):
testChildWindow dlgBox = new testChildWindow();
dlgBox.DataContext = (this.DataContext as IAssignDlgViewModel).AssignVM("defaultChildWindow");
dlgBox.Show();
Data Context/Member variable:
public class testChildWindowViewModel : IDlgViewUpdate
{
public User
...
}
public class User
{
public bool showUser;
public User()
{
showUser = true;
}
...
}
If I make the Vm's binding source property (showUser) a dependency property at the (non-nested) testChildWindowViewModel, then the binding works. But all other combinations seem to fail.
Why must it be a dependency (or INotifyPropertyChanged?) property for a 1-time binding?
Why can't I get it to work at a nested level?
Thanks!!!
Ah, looking at the Output window during the binding answered the question for me. The problem was that User was not a property. Changed it to an auto property and the binding works just right now.
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