Follow is CSharp code, and I want to use the attached property Angle to change the rectangles' angle in my XAML. The problem is when I change the new PropertyMetadata(0.0,OnAngleChanged) tonew PropertyMetadata(0,OnAngleChanged) then it doesn't work and throw XamlParseException and says that the type initializer for XXX.RotationManager threw an exception. I wonder why new PropertyMetadata(0,OnAngleChanged) does't work.
class RotationManager
{
public static double GetAngle(DependencyObject obj)
{
return (double)obj.GetValue(AngleProperty);
}
public static void SetAngle(DependencyObject obj, double value)
{
obj.SetValue(AngleProperty, value);
}
// Using a DependencyProperty as the backing store for Angle. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty =
DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(RotationManager), new PropertyMetadata(0.0,OnAngleChanged));
private static void OnAngleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as UIElement;
if (element!=null)
{
element.RenderTransformOrigin = new Point(.5, .5);
element.RenderTransform = new System.Windows.Media.RotateTransform((double)e.NewValue);
}
}
}
because the first parameter of PropertyMetaData() is the same type as GetAngle and SetAngle, when you change the type of GetAngle and SetAngle to int, and the new PropertyMetadata(0,OnAngleChanged) can work.
However, changing the property type to int isn't feasible. It should have the same type as the property that it is assigned to later, i.e. RotateTransform.Angle, which is double.
The best solution would be to not specify a default value at all, and thus implicitly get 0.0 or default(double) as default value:
public static readonly DependencyProperty AngleProperty =
DependencyProperty.RegisterAttached(
"Angle", typeof(double), typeof(RotationManager),
new PropertyMetadata(new PropertyChangedCallback(OnAngleChanged)));
Related
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;
}
I have problem with binding in code.
I have Control with X, Y double properties and dependency properties.
public double X
{
get { return (double)GetValue(XProperty); }
set
{
SetValue(XProperty, value);
}
}
public double Y
{
get { return (double)GetValue(YProperty); }
set
{
SetValue(YProperty, value);
}
}
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
In other control I have Line and I try to use binding to Line end point like this:
var xBinding = new Binding("XProperty") {Source = _startPin};
var yBinding = new Binding("YProperty") {Source = _startPin};
Line.SetBinding(Line.X1Property, xBinding);
Line.SetBinding(Line.Y1Property, yBinding);
All data in all properties are OK, I checked that, but binding doesn't work. I don't have idea why... (All controls are on one Canvas)
Thank you very much!
To debug this kind of situation you should look at the XAML by using a tool like snoop WPF. This will show what the actual bindings are.
It might be your binding is there, but not updating. To fix this your class should implement INotifyPropertyChanged. Whenever you want to update the value, like after setting the value, call the following function with the name of the property:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
I am sorry, my fault. Problem was in first parameter in register dependency property.
public static readonly DependencyProperty XProperty = DependencyProperty.Register("X", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("Y", typeof(double), typeof(VisualPin));
Instead of:
public static readonly DependencyProperty XProperty = DependencyProperty.Register("XProperty", typeof(double), typeof(VisualPin));
public static readonly DependencyProperty YProperty = DependencyProperty.Register("YProperty", typeof(double), typeof(VisualPin));
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 :)
I have created a custom attached behaviour:
public static class CustomItemsBehaviour
{
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(ItemsControl),
new UIPropertyMetadata(""));
public static string GetMyTest(ItemsControl itemsControl)
{
return (string)itemsControl.GetValue(MyTestProperty);
}
public static void SetMyTest(ItemsControl itemsControl, string value)
{
itemsControl.SetValue(MyTestProperty, value);
}
}
I am trying to use it like so:
<ListBox
ItemsSource="{Binding Path=Items}"
AttachedBehaviours:CustomItemsBehaviour.MyTest="{Binding TestValue}">
But it fails with:
{"A 'Binding' cannot be set on the 'SetMyTest' property of type 'ListBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject."}
I want to bind some value in my view model to the value of MyTest. Is this possible to do?
The problem is in your registration code. You should pass typeof(CustomItemsBehaviour) as owner type:
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(CustomItemsBehaviour),
new UIPropertyMetadata(""));
I'm not sure what you are trying to acheive, but i think there is some mistakes in the declaration of your attached property. Try this :
public static class CustomItemsBehaviour
{
public static readonly DependencyProperty MyTestProperty =
DependencyProperty.RegisterAttached(
"MyTest",
typeof(string),
typeof(CustomItemsBehaviour),
new UIPropertyMetadata(""));
public static string GetMyTest(DependencyObject itemsControl)
{
return (string)itemsControl.GetValue(MyTestProperty);
}
public static void SetMyTest(DependencyObject itemsControl, string value)
{
itemsControl.SetValue(MyTestProperty, value);
}
}
See here DependencyProperty.RegisterAttached
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);
}
}
}