I am new to WPF so after reading for a while I deduce that my problem needs to be handled with this pattern: DependencyProperty.
I want my ToggleButton to have another boolean property.
My problem is where should I assign this property, and how? Inside the object that is bound to the ToggleButton?
Let's say I have a class cell (which is bound to this Button) that when clicked I want that from this point on, it would hold new face with trigger on.
My new property will be:
bool wasClick
Can someone explain to me how I should write it and tell me more about this new concept?
EDIT:
The main topic is where should I define it so I want it asoocited to a Button but where should I write the code. Lets say I have a class that is bound to a Button. Should I write:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
... "IsSpinning", typeof(Boolean),
in this class or should I write it in my view model? If so, where and how?
As the name implies (kind of poorly), a dependency property is a property whose value can depend on something else. Generally, this means a property whose value gets determined automatically (and dynamically) by the WPF framework under certain conditions. The most common conditions are:
The property has a default value, or inherits its value from an ancestor in the visual tree. In this case, the property's value is determined without it ever being set.
The property is the target of data binding.
The property's value is set by an animation.
Not all properties whose value gets set by the WPF framework need to be dependency properties. Any CLR property with a public getter and setter can be the source of a two-way data binding.
In your case, it sounds like you don't really need a dependency property, not if you're using a view model. You could just do this (assuming that you've implemented property-change notification in your class):
private bool _IsChecked;
public bool IsChecked
{
get { return _IsChecked; } }
set
{
if (value == _IsChecked)
{
return;
}
_IsChecked = value;
WasChecked = WasChecked || value;
OnPropertyChanged("IsChecked");
}
}
private bool _WasChecked;
public bool WasChecked
{
get { return _WasChecked; }
private set
{
if (value == _WasChecked)
{
return;
}
_WasChecked = value;
OnPropertyChanged("WasChecked");
}
}
Related
I found a difference on property binding between UserControl and a normal Control.
For example, assuming that the markup contains the following usercontrol:
<myCtrl:DemoControl Level="{Binding Alarm.AlarmLevel}" />
"Level" is an int dependency property created in "Control". "Alarm" is an object of type Inotifypropertychanged, with a field AlarmLevel.
public bool AlarmLevel
{
get
{
return this._alarmLevel;
}
set
{
this._alarmLevel = value;
NotifyPropertyChanged("AlarmLevel");
}
}
Inside the usercontrol, I did the following:
LevelProperty = DependencyProperty.Register("Level", typeof(int), typeof(DemoControl), new UIPropertyMetadata(0, isLevelChanged));
The strange thing is that when assign AlarmLevel to a value, if the value changes, the usercontrol property got updated. While if value remains the same, no update. BUT IN BOTH CASES, "NotifyPropertyChanged" gets called !
For example, if AlarmLevel==1,
Alarm.AlarmLevel = 2; // the "isLevelChanged" got called
Alarm.AlarmLevel = 1; // the "isLevelChanged" not called
I remember that with the normal control, whenever PropertyChanged is called, the property gets updated. Anybody knows why? Many thanks!
There is a bug in your AlarmLevel setter. It should be:
if (_alarmLevel != value)
{
this._alarmLevel = value;
NotifyPropertyChanged("AlarmLevel");
}
You should only raise the INotifyPropertyChanged when the value actually changes. When you use INotifyPropertyChanged, the change check is your responsibility. When you you dependency properties, the WPF framework does the check for you.
That's why your code is half working :).
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...
I'm having some problems with data binding in WPF. Here's the scenario: I have made a user control which simulates a Dial Pad (i.e., an array of 12 buttons with the digits from '0' to '9' plus the '#' and 'Clear' keys). The control lives inside a class library and it's been implemented following the MVVM pattern, mainly because I need the components in the class library to be easily unit tested.
The view model for the control is quite simple, it basically updates a public "DialedNumber" string (which is internally connected to the model) every time the user presses a dial pad key button. The binding is working correctly and, by using the debugger, I can confirm that the "DialedNumber" variable inside the viewmodel is getting updated as I press button in the dial pad.
This DialPad control is used by a separate XAML file (Panel.xaml), which laids out several controls that belong to my custom class library.
Now, I'd like to add a TextBlock inside my Panel file in order to display the "DialedNumber" string held inside the DialPad. This is the code snippet in Panel.xaml:
<PanelControls:DialPad x:Name="MyDialPad" DialedNumber="55325"/>
<TextBlock Text="{Binding ElementName=MyDialPad, Path=DialedNumber}" />
The result I'm getting is that the textblock displays the correct number on start (i.e., "55325"), but its content doesn't get updated as I press the dial pad keys (even though the DialPad's viewmodel gets updated as I press new keys, as I've checked with the debugger).
Here's the code behind for the DialPad view:
public partial class DialPad : UserControl
{
public DialPad()
{
InitializeComponent();
DataContext = new DialPadViewModel();
}
public void DialedNumberChanged(object sender, EventArgs e)
{
return;
}
public DialPadViewModel DialPadViewModel
{
get { return DataContext as DialPadViewModel; }
}
public string DialedNumber
{
get
{
var dialPadViewModel = Resources["DialPadVM"] as DialPadViewModel;
return (dialPadViewModel != null) ? dialPadViewModel.DialedNumber : "";
}
set
{
var dialPadViewModel = Resources["DialPadVM"] as DialPadViewModel;
if (dialPadViewModel != null)
{
dialPadViewModel.DialedNumber = value;
}
}
}
}
Here's the DialPad view model:
public class DialPadViewModel : ObservableObject
{
public DialPadViewModel()
{
_dialPadModel = new DialPadModel();
}
#region Fields
private readonly DialPadModel _dialPadModel;
private ICommand _dialPadKeyPressed;
#endregion
#region Public Properties/Command
public DialPadModel DialPadModel
{
get { return _dialPadModel; }
}
public ICommand DialPadKeyPressedCommand
{
get
{
if (_dialPadKeyPressed == null)
{
_dialPadKeyPressed = new RelayCommand(DialPadKeyPressedCmd);
}
return _dialPadKeyPressed;
}
}
public string DialedNumber
{
get { return _dialPadModel.DialedNumber; }
set
{
_dialPadModel.DialedNumber = value;
RaisePropertyChanged("DialedNumber");
}
}
#endregion
#region Private Helpers
private void DialPadKeyPressedCmd(object parameter)
{
string keyPressedString = parameter.ToString();
if (keyPressedString.Length > 0)
{
if (char.IsDigit(keyPressedString[0]))
{
DialedNumber += keyPressedString[0].ToString(CultureInfo.InvariantCulture);
}
else if (keyPressedString == "C" || keyPressedString == "Clr" || keyPressedString == "Clear")
{
DialedNumber = "";
}
}
}
#endregion
}
Let me restate my problem: the textblock in Panel.xaml displays the correct number (55325) on start, but its value never gets updated as I press the DialPadButtons. I've placed a breakpoint inside DialPadKeyPressedCmd and I can confirm that the method gets executed everytime I press a key in the dial pad.
DependencyProperties are meant to point to some other property to get their value. So you can either point it to your DialPadViewModel.DialedNumber, or you can point it to some other string when the UserControl is used (either a binding or a hardcoded value like "551"), but you can't do both.
In your case, when someone binds to the DialedNumber dependency property, they are replacing the current value (the binding to DialPadViewModel.DialedNumber) with a new value.
Depending on how your code looks and what you want to do, there are a few ways around it.
First, you could insist that people who want to use your control also use your ViewModel, and don't make DialedNumber a public dependency property.
So instead of being allowed to create a custom class with a property of SomeOtherDialedNumber and binding
<DialPad DialedNumber="{Binding SomeOtherDialedNumber}">
they are forced to use the DialPadViewModel in their code anytime they want to use the DialPad control. For this to work, you would need to remove the this.DataContext = new DialPadViewModel in your code-behind the UserControl since the user will be providing the DialPadViewModel to your UserControl, and you can use an implicit DataTemplate to tell WPF to always draw DialPadViewModel with your DialPad UserControl.
<DataTemplate DataType="{x:Type DialPadViewModel}">
<local:DialPad />
</DataTemplate>
The other alternative I can think of is to synchronize your DependencyProperty with your ViewModel property with some PropertyChange notifications.
You would need to update DialPadViewModel.DialedNumber anytime the DialedNumber dependency property changes (You may need to use DependencyPropertyDescriptor.AddValueChanged for property change notification), and you would also have to write something to update the source of the DialedNumber dependency property anytime DialPadViewModel.DialedNumber changes.
Personally, if my UserControl has a ViewModel then I use the first option. If not, I get rid of the ViewModel entirely and build the logic for my UserControl in the code-behind, without a ViewModel.
The reason for this is that WPF works with two layers: a UI layer and a data layer. The DataContext is the data layer, and a ViewModel is typically part of the data layer. By setting the data layer (DataContext) explicitly in the UserControl's constructor, you are combining your data layer with your UI layer, which goes against one of the biggest reasons for using MVVM: separation of concerns. A UserControl should really just be a pretty shell only, and you should be able to place it on top of any data layer you want.
If you place your DialPad in your View, you can create a DialPadViewModel-Property (public+global) in your ViewViewModel:
public DialPadViewModel DialPadViewModel = new DialPadViewModel();
Now set the DataContext-Binding of your View to the ViewViewModel and bind the DialPads DataContext also to it, like
<local:DialPad DataContext="{Binding}"/>
Now you can bind to the properties in your DialPadViewModel:
<TextBox Text="{Binding Path=DialPadViewModel.DialedNumber}"/>
Thats how you can Access your DialPadViewModel from your View and your DialPad.
EDIT:
Now try changing your DialedNumber Property in your DialPad.xaml.cs like this:
public string DialedNumber
{
get
{
return DialPadViewModel.DialedNumber;
}
set
{
DialPadViewModel.DialedNumber = value;
}
}
EDIT 2: I found the Problem:
In your DialPad.xaml all your Commands were bound to the DialPadViewModel from the resources, while the TextBloc was bound to the DialPads DataContext, which is another instance of the DialPadViewModel.
So everytime you hit a DialPad-Button you changed the value of the DialedNumber from the resources' DPVM-instance not the DialedNumber from the DataContext's DPVM-instance.
It sounds like you can add a TextBox to your view and bind it's Text property to your view-model's DialedNumber property.
<TextBox Text="{Binding Path=DialedNumber}"></TextBox>
Your view-model property can look something like this:
private string _dialedNumber;
[DefaultValue("551")]
public string DialedNumber
{
get { return _dialedNumber; }
set
{
if (value == _dialedNumber)
return;
_dialedNumber= value;
_yourModel.DialedNumber= _dialedNumber;
this.RaisePropertyChanged("DialedNumber");
}
}
Let me know if I misunderstood your question.
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.
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"/>