Here is my problem. I recently created a custom control, which works pretty well.
But i have a problem when i use it, i have a little problem :
In my control, i made a property named Value, defined like this :
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown), new PropertyMetadata(1000));
public int Value
{
get
{
return (int)GetValue(ValueProperty);
}
set
{
SetValue(ValueProperty, value);
this.ValueText.Text = value.ToString();
}
}
When I do a databinding to this value, the binding works, but the default value is set to 1000, so it first print 1000. But actually, the property bound to Value isn't equal to 1000.
I would like to print in ValueText.Text the value of the bound property when the Value property is created.
Edit : Question is simple, how can I remove that default value and directly print the bound property ?
You should be able to setup a PropertyChanged event in your DependancyProperties metadata to update ValueText when Value changes.
somthing like this:
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(int), typeof(NumericUpDown),
new PropertyMetadata(1000, (sender, e) => (sender as NumericUpDown).ValueText.Text = e.NewValue.ToString()));
public int Value
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
The property setter will not get called as things change via WPF's data binding, so this technique will not work.
The default, initial value will always be 1000, but data binding may override it. You will need to add a Callback to appropriately notify you when the dependency property value is changed.
For details, see the Dependency Property Callbacks page to see how to implement a property changed callback correctly. This is the appropriate place to set your other (ValueText) property.
Related
My control has a property that maps to a private variable. When the property is set, I also need to store a certain other variable. When the private variable of the property is set by my own control code, this special handling must not occur. All good.
I now need to refactor that to a DependencyProperty. I only have a change handler here, and all (also internal) accesses to that property must go through the DependencyProperty framework. There is no more private variable that I could set directly. Every change done by my own code now looks exactly the same as changes from external sources like the user of the control or DataBinding.
In my property change handler, how can I determine whether a value change came from my code or somewhere else?
This is the old code:
private DateTime selectedTime;
private int intendedDay;
public DateTime SelectedTime
{
get { return selectedTime; }
set
{
selectedTime = value;
intendedDay = selectedTime.Day;
}
}
In this code, I can set selectedTime directly, not affecting intendedDay which must only be set when SelectedTime is assigned a new value altogether from the outside, or when I see fit in my control.
The DependencyProperty only allows me to detect any changes:
public static DependencyProperty SelectedTimeProperty = DependencyProperty.Register(
"SelectedTime",
typeof(DateTime),
typeof(DateTimeTextBox),
new PropertyMetadata(SelectedTimeChanged));
public DateTime SelectedTime
{
get { return (DateTime) GetValue(SelectedTimeProperty); }
set { SetValue(SelectedTimeProperty, value); }
}
private static void SelectedTimeChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
DateTimeTextBox control = (DateTimeTextBox) obj;
// This must not happen where I previously assigned the private variable:
control.intendedDay = control.SelectedTime.Day;
}
private int intendedDay;
So when I would previously assign the private variable, I can now only set the dependency property, which will also change intendedDay.
Why not wrap your dependency property in a normal property? Setting the property will still set the dependency property and setting the private one will not set the intendedDay value.
private DateTime selectedTime
{
get { return (DateTime) GetValue(SelectedTimeProperty); }
set { SetValue(SelectedTimeProperty, value); }
}
public DataTime SelectedTime
{
get { return selectedTime; }
set
{
selectedTime = value;
intendedDay = selectedTime.Day;
}
}
Like Clemens explained in his comment, I added a private variable that indicates whether I am currently updating that property from my own code. I set it to true whenever I want to suppress external value change handling, and false afterwards. So I can distinguish whether it was an internal or external value change.
I created a control, derived from Canvas, that should plot a live diagram, given values that are passed via a binding to a DependencyProperty. The simplified version is this:
public class Plotter : Canvas
{
public float Value { get { return (float)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(float), typeof(Plotter),
new PropertyMetadata(0f, new PropertyChangedCallback(ValueChangedCallBack)));
public static void ValueChangedCallBack(DependencyObject property, DependencyPropertyChangedEventArgs args)
{
Plotter plotter = (Plotter)property;
plotter.Value = (float)args.NewValue; //<-- Removed this line to get it to work
// Actually draw the value into the canvas geometry
plotter.PlotValue(plotter.Value);
}
}
I bound the control like this:
<mystuff:Plotter Value="{Binding MyViewModelProperty}" Height="50" Width="200" />
My ViewModel implements INotifyPropertyChanged and calls PropertyChanged correctly. If I bind MyViewModelProperty to a textbox, it correctly updates every time. Only if I bind it to my own control, my ValueChangedCallBack is only called once as the page is loaded, and then never again.
What am I not seeing here? Thanks for any help!
Solved: I dont have to set the Value explicitly in the callback.
You set the property Value on the callback for the property Value changing. That doesn't make much sense in any case. But is that locally set value overriding the binding value, causing your binding to no longer be set on the dependency property?
Do you need to set the Mode of your binding to TwoWay?
Should you not be using DependencyProperty.Register instead of DependencyProperty.RegisterAttached?
There are plenty of ways to bind a SOURCE method to target property, either by ValueConverter or by ObjectDataProvider. However, what if I want to have the binding affect the target METHOD?
Consider the following example:
class ListBoxViewModel
{
public static readonly DependencyProperty CurrentItemProperty = DependencyProperty.Register("CurrentItem", typeof (object), typeof (ListBoxViewModel));
public object CurrentItem
{
get { return (object) GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
}
I'd like to bind the property CurrentItem to ListBox's CollectionView. However, since the CurrentItem property of CollectionView is read-only, I can't bind to it directly. Instead, I have to execute MoveCurrentToPosition function. How can I do it?
If there is a different way to do that - Without binding to a method, I'd love to hear it too, however, the main question is how to bind to a method, if not in this case, then in a similar one. If it is impossible, what is the best alternative? E.g one idea that comes to mind is subscribing to the change notification of the dependency property (CurrentItem in this case) and running the procedural code from that function.
Thanks!
You can register your property with a property changed callback in which you then can update the CollectionView manually:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register
(
"CurrentItem",
typeof(object),
typeof(ListBoxViewModel),
new UIPropertyMetadata(null, CurrentItemChanged)
);
public object CurrentItem
{
get { return (object)GetValue(CurrentItemProperty); }
set { SetValue(CurrentItemProperty, value); }
}
private static void CurrentItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Update current item logic
}
I may be doing this all wrong... so hang with me
I am making a user control with a property which the user can bind to. The in setter for the property, I bind the PropertyChanged listener to the property so I can react to changes to its state. The code behind for this user control looks like this:
public static readonly DependencyProperty NodeProperty =
DependencyProperty.Register("Node", typeof(MockRequirementWrapper), typeof(RecNode2));
public MockRequirementWrapper Node
{
get
{
return (MockRequirementWrapper)GetValue(NodeProperty);
}
set
{
if(Node != null)
Node.PropertyChanged -= Update;
SetValue(NodeProperty, value);
Node.PropertyChanged += new PropertyChangedEventHandler(Update);
OnPropertyChanged(this, "Node");
}
}
then, in another user control, I bind to this property a node I've created elsewhere like this:
<local:RecNode2 Node="{Binding}"/>
What I am finding is the recnode exists and is bound to a node... but if I put a breakpoint in the setter, it never gets called. Am I misunderstanding how the binding works? How do I add my listener when the node changes?
The framework will always call GetValue and SetValue directly, the property is just for convenience and sould never contain logic besides those calls.
If you want to do something on changes register a PropertyChangedCallback in the Metadata when registering the DependencyProperty.
Taken from http://msdn.microsoft.com/en-us/library/ms753358.aspx:
public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}
I have a dependency property on a control which is a custom class.
Now is there an event that gets raised BEFORE the value is being changed?
I know that OnPropertyChanged is raised after the property has already changed.
I need some event before so that I can cancel the changing....in order to preserve the state of the control.
I cannot set back the dependency property back to its old value as that will mean that I lose state in the control.
Thanks!
If its your DependencyProperty, you can use the ValidateValueCallback to validate the incoming value and reject it, if its not as you desire.
In the following example, only values greater than 0 will be accepted:
public int Test {
get { return (int)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(int), typeof(YourClass),
new UIPropertyMetadata(0), delegate(object v) {
return ((int)v) > 0; // Here you can check the value set to the dp
});
If your data objects implement INotifyPropertyChanging, then you can handle the PropertyChanging event which is raised before the property value changes.
INotifyPropertyChanging was introduced in .NET 3.5
You may check value of property in property declaration set section. Suppose we have CustomColor dep property:
public Color CustomColor
{
get { return GetValue(CustomColorProperty) as Color;}
set
{
//check value before setting
SetValue(CustomColorProperty, value);
}
}
Also there will be helpfull for you PropertyChangedCallback, ValidateValueCallback, CoerceValueCallback delegates.