Adding logic to a User Control in WPF - c#

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 :)

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)

WPF Code binding not work

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));

Binding to attached behaviours

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

Shared dependency property update issue in binding

I have a read-only dependency property which is shared between two WPF classes. So I made this property shared property. While binding this property on XAML, It takes its default value and can't be updated. But If I use the main owner of this property, its value can be updated.
So what is your advice?
public class A
{
private static readonly DependencyPropertyKey XPropertyKey =
DependencyProperty.RegisterReadOnly("X",
typeof(Point), typeof(A),
new FrameworkPropertyMetadata(new Point(0, 0),
FrameworkPropertyMetadataOptions.Inherits |
FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty XProperty =
RelativeMousePointPropertyKey.DependencyProperty;
public Point X
{
get { return (Point)GetValue(XProperty); }
set { SetValue(XProperty, value); }
}
public void SetRelativeMousePoint(Point point)
{
SetValue(XPropertyKey, point);
}
}
public class B
{
//I use this class for binding
public static readonly DependencyProperty XProperty =
A.XProperty.AddOwner(typeof(B));
public Point X
{
get { return (Point)GetValue(X); }
}
}

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