Private WPF dependency property - c#

In my WPF project I need to animate several properties with the same value. So my idea was to create a custom, private dependency property to which the animation will be applied. Unfortunately this doesn't seem to work. DependencyPropertyDescriptor.FromProperty() always returns null for this property. Here is the code:
public partial class PedestrianVisual : UserControl {
private static readonly DependencyProperty CurrentInaccuracyRadiusProperty =
DependencyProperty.Register("CurrentInaccuracyRadius", typeof(double), typeof(PedestrianVisual));
private double CurrentInaccuracyRadius {
get { return (double)GetValue(CurrentInaccuracyRadiusProperty); }
set { SetValue(CurrentInaccuracyRadiusProperty, value); }
}
public PedestrianVisual() {
InitializeComponent();
// This returns "null" all the time.
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(
CurrentInaccuracyRadiusProperty, typeof(PedestrianVisual));
dpd.AddValueChanged(this, (s, e) => {
UpdateInaccuracyCircle((double)GetValue(CurrentInaccuracyRadiusProperty));
});
}
private void UpdateInaccuracyCircle(double curRadius) {
// do something here
}
}
Is there any other way to create a private dependency property?

I don't understand why you would do it that way, i did not encounter any problems when attaching the callback in the declaration, e.g. something like this:
private static readonly DependencyProperty CurrentInaccuracyRadiusProperty =
DependencyProperty.Register
(
"CurrentInaccuracyRadius",
typeof(double),
typeof(PedestrianVisual),
new UIPropertyMetadata(0.0, (s, e) =>
{
UpdateInaccuracyCircle((PedestrianVisual)s, (double)e.NewValue);
})
);
(UpdateInaccuracyCircle method should be static in this case)
If you want to stick with the instance method:
private static readonly DependencyProperty CurrentInaccuracyRadiusProperty =
DependencyProperty.Register
(
"CurrentInaccuracyRadius",
typeof(double),
typeof(PedestrianVisual),
new UIPropertyMetadata(0.0, (s, e) =>
{
((PedestrianVisual)s).UpdateInaccuracyCircle((double)e.NewValue);
})
);

To further update H.B's answer, the standard approach is along these lines:
static readonly DependencyProperty CurrentInaccuracyRadiusProperty =
DependencyProperty.Register
(
"CurrentInaccuracyRadius",
typeof(double),
typeof(PedestrianVisual),
new UIPropertyMetadata(0.0, OnCurrentInaccuracyRadiusChanged)
);
static void OnCurrentInaccuracyRadiusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var pedVisual = d as PedestrianVisual;
if (pedVisual != null)
pedVisual.OnCurrentInaccuracyRadiusChanged((double)e.OldValue, (double)e.NewValue);
}
void OnCurrentInaccuracyRadiusChanged(double oldValue, double newValue)
{
UpdateInaccuracyCircle(newValue);
}

Related

Add IsDirty-Flag on TextBox with DependencyProperty

I have the problem, that I have a existing model object which i canĀ“t extend. The actual problem is a bit more complex, so i try to break it down.
I want to extend a TextBox with a dependency property to indicate the text has changed. So i came up with following solution:
public class MyTextField : TextBox
{
public MyTextField()
{
this.TextChanged += new TextChangedEventHandler(MyTextField_TextChanged);
}
private void MyTextField_TextChanged(object sender, TextChangedEventArgs e)
{
IsDirty = true;
}
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
"IsDirtyProperty",
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
public bool IsDirty
{
get { return (bool)GetValue(IsDirtyProperty); }
set { SetValue(IsDirtyProperty, value); }
}
}
XAML:
<my:MiaTextField Text="{Binding Barcode}" IsDirty="{Binding IsDirty}"/>
So if I change the text in the TextBox, the isDirty Property should change to true.
But I got a System.Windows.Markup.XamlParseException: Binding can only set for a "DependencyProperty" of "DependencyObject".
Pass "IsDirty", i.e. the name of the CLR wrapper for the dependency property, to the DependencyProperty.Register method:
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
"IsDirty",
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
If you are using C#6 / Visual Studio 2015 or later, you could use the nameof operator:
public static DependencyProperty IsDirtyProperty = DependencyProperty.Register(
nameof(IsDirty),
typeof(bool),
typeof(MyTextField),
new PropertyMetadata(false));
Alternatively you could override the PropertyMetadata of the TextProperty:
public class MyTextBox : TextBox
{
static MyTextBox()
{
TextProperty.OverrideMetadata(typeof(MyTextBox), new FrameworkPropertyMetadata("", IsDirtyUpdateCallback));
}
private static void IsDirtyUpdateCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is MyTextBox tb && e.NewValue != e.OldValue && e.Property == TextProperty)
{
tb.IsDirty = (string)e.OldValue != (string)e.NewValue;
}
}
public bool IsDirty
{
get { return (bool)GetValue(IsDirtyProperty); }
set { SetValue(IsDirtyProperty, value); }
}
public static readonly DependencyProperty IsDirtyProperty =
DependencyProperty.Register("IsDirty", typeof(bool), typeof(MyTextBox), new PropertyMetadata(true));
}
to automatically set your IsDirty :o) more then one way to rome. But for your proplem thats kinda Shooting small birds with cannons (German proverb)

cannot convert from method group to object porting WFP => UWP

For a project i've been working on i'm porting some custom controls from the WPF platform to UWP.
on the WPF side it is implemented as such:
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register("MaxLength", typeof(int), typeof(HexBox), new PropertyMetadata(MaxLength_PropertyChanged));
public int MaxLength
{
get { return (int)GetValue(MaxLengthProperty); }
set { SetValue(MaxLengthProperty, value); }
}
private static void MaxLength_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
HexBox hexControl = (HexBox)d;
hexControl.txtValue.MaxLength = (int)e.NewValue;
}
with the MaxLength_PropertyChanged being used without arguments.
When i try to do the same in UWP i get greeted by the following message:
Argument 1: cannot convert from 'method group' to 'object'
I know this has to do with not passing the arguments, or calling them as a method with (). but in WPF this behavior was implicit.
anyone have an idea?
Try this:
public static readonly DependencyProperty MaxLengthProperty = DependencyProperty.Register(
"MaxLength",
typeof(int),
typeof(HexBox),
new PropertyMetadata(0, new PropertyChangedCallback(MaxLength_PropertyChanged))
);
private static void MaxLength_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
HexBox hexControl = d as HexBox;
hexControl.txtValue.MaxLength = (int)e.NewValue;
}

Adding logic to a User Control in WPF

I'm creating a simple User Control with three properties. For simplicity let's assume these are A, B and C. Moreover C = A + B. I want to display all of them in TextBoxes (A, B - User Editable, C - read only). Whenever a user modifies A or B, the value of C should be updated.
I've already created Dependency Properties for A and B in MyControl.xaml.cs file.
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(0.0));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
My question is: what shall I do with C and where its definition should be kept ? Should the logic be coded inside a control or maybe it's a user's responsibility to remember about the relationship between the properties ?
You should declare another DependencyProperty for C in the UserControl and add property change handlers to your A and B properties to update the value of C when their values change. This should do the job:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new UIPropertyMetadata(0.0, OnAOrBPropertyChanged));
public static void OnAOrBPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
dependencyObject.SetValue(CProperty, (double)dependencyObject.GetValue(AProperty) +
(double)dependencyObject.GetValue(BProperty));
}
You might like to view the Read-Only Dependency Properties page on MSDN for help with declaring a read-only DependencyProperty.
You need to make another dependency property for C also
You can try this:
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double A
{
get { return (double)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(OnAorBChange));
public double B
{
get { return (double)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
public static readonly DependencyProperty CProperty =
DependencyProperty.Register("C", typeof(double),
typeof(MyControl), new FrameworkPropertyMetadata(null));
public double C
{
get { return (double)GetValue(CProperty); }
set { SetValue(CProperty, value); }
}
private static void OnAorBChange(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
var obj1 = obj as MyControl;
obj1.C = obj1.A + obj1.B;
}
I assume you did the proper binding :)

Attached Property + Style -> ArgumentNullException

I have created a very Simple attached Property:
public static class ToolBarEx
{
public static readonly DependencyProperty FocusedExProperty =
DependencyProperty.RegisterAttached(
"FocusedEx", typeof(bool?), typeof(FrameworkElement),
new FrameworkPropertyMetadata(false, FocusedExChanged));
private static void FocusedExChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is ToolBar)
{
if (e.NewValue is bool)
{
if ((bool)e.NewValue)
{
(d as ToolBar).Focus();
}
}
}
}
public static bool? GetFocusedEx(DependencyObject obj)
{
return (bool)obj.GetValue(FocusedExProperty);
}
public static void SetFocusedEx(DependencyObject obj, bool? value)
{
obj.SetValue(FocusedExProperty, value);
}
}
Setting this in Xaml works perfectly fine, but if I try setting it within a Style:
I receive an ArguemntNullException during the Runtime (saying: "Value cannot be null.
Parameter name: property").
I cannot figure what is wrong here. Any hint is appriciated!
A common mistake made when registering attached dependency properties is to incorrectly specify the ownerType argument. This must always be the registering class, ToolBarEx here:
public static readonly DependencyProperty FocusedExProperty =
DependencyProperty.RegisterAttached(
"FocusedEx", typeof(bool?), typeof(ToolBarEx),
new FrameworkPropertyMetadata(false, FocusedExChanged));
And just for avoiding unnecessary code in the property changed handler you could safely cast NewValue to bool:
private static void FocusedExChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var toolBar = d as ToolBar;
if (toolBar != null && (bool)e.NewValue)
{
toolBar.Focus();
}
}

How can I create a read-only Boolean dependency property that returns `And` operation between two other dependency properties

How can I create a custom read-only Boolean dependency property that returns And operation between two custom Boolean dependency properties, for example (A, B),
And when A or B changes, I want the result property to trigger.
Any help to achieve that!
Part 1: dependencies.
public static readonly DependencyProperty Source1Property =
DependencyProperty.Register(
"Source1",
typeof(bool),
typeof(MyControl),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(UpdateTarget)));
public bool Source1
{
get { return (bool)GetValue(Source1Property); }
set { SetValue(Source1Property, value); }
}
void UpdateTarget(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyControl self = (MyControl)d;
d.Target = d.Source1 && d.Source2;
}
Part 2: read-only
internal static readonly DependencyPropertyKey TargetPropertyKey =
DependencyProperty.RegisterReadOnly(
"Target",
typeof(bool),
typeof(MyControl),
new PropertyMetadata(false));
public static readonly DependencyProperty TargetProperty =
TargetPropertyKey.DependencyProperty;
public bool Target
{
get { return (bool)GetValue(TargetProperty); }
protected set { SetValue(TargetPropertyKey, value); }
}
Disclaimer: I didn't try the part 2.
Part 3:
if the source dependency properties are not defined by you, you can do the following trick:
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(
MyControl.Source1Property,
typeof(MyControl)));
if (dpd != null)
dpd.AddValueChanged(this, UpdateTarget);
You can do this by defining your two dependency properties A and B (for the sake of the example, I guess), and define a callback to be executed whenever these changes, using PropertyMetaData in the DependencyProperty constructor. In this callback, simply perform the calculation you want and set the Result depdendency property to that value. Here is a working example:
public class Data : DependencyObject
{
public static readonly DependencyProperty AProperty = DependencyProperty.Register("A", typeof(Boolean), typeof(Data), new PropertyMetadata(false,HandleValueChanged));
public static readonly DependencyProperty BProperty = DependencyProperty.Register("B", typeof(Boolean), typeof(Data), new PropertyMetadata(false, HandleValueChanged));
public static readonly DependencyProperty ResultProperty = DependencyProperty.Register("Result",typeof (Boolean), typeof (Data));
private static void HandleValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(ResultProperty, ((Data)d).Result);
Debug.WriteLine("Value change");
}
public bool Result
{
get { return A & B; }
}
public bool A
{
get { return (bool) GetValue(AProperty); }
set
{
if ( A != value )
SetValue(AProperty, value);
}
}
public bool B
{
get
{
return (bool) GetValue(BProperty);
}
set
{
if (B != value)
SetValue(BProperty, value);
}
}
}

Categories