Binding doesn't get updated - wpf

I have class deriving from TextBox to which I attach a dependency property of type point called position and in its set section I set the Canvas.Top and Canvas.Left property. Just to clarify, whenever the source property changes it calls the set section of the property correct? Because when my source updates the canvastop and canvasleft properties of the textbox don't get updated.
Any help would be appreciated.
public static readonly DependencyProperty PositionProperty = DependencyProperty.Register("Position", typeof(Point), typeof(TextBox), new FrameworkPropertyMetadata(new Point(0, 0)));
public Point Position
{
get { return (Point)GetValue(PositionProperty); }
set
{
SetValue(PositionProperty, value);
Canvas.SetLeft(this, value.X - this.Width / 2);
Canvas.SetTop(this, value.Y - this.FontSize);
}
}
this.TextBoxShape.SetBinding(TextBoxShape.PositionProperty, CreateConnectorBinding(this));
Where CreateConnectorBinding returns the mid point of an ellipse based on it Canvas.Top and Canvas.Left properties. But when the Ellipse's Canvas.Top and Canvas. Left properties get updated the position of the textbox is still not updated.

Just to clarify, whenever the source property changes it calls the set section of the property correct?
No. This only happens when you call the property from code. The binding system bypasses the setter entirely.
If you need to do this, the proper way is to use Property Changed Callbacks registered in the DP's Metadata.

When the PositionProperty value changes via the binding, it does not use the setter. You need to add a PropertyChangeCallback to the FrameworkPropertyMetadata on your DependencyProperty registration:
public static readonly DependencyProperty PositionProperty =
DependencyProperty.Register("Position", typeof(Point), typeof(TextBox),
new FrameworkPropertyMetadata(new Point(0, 0), PositionChanged));
private static void PositionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
YourControl control = (YourControl)d;
Canvas.SetLeft(d, d.Position.X - d.Width / 2);
Canvas.SetTop(d, d.Position.Y - d.FontSize);
}

Related

Notify if xaml calls SetValue() of a Dependency Property

I want to draw lines in UserControls that are in a ListBox. The number of lines is a Dependency Property and is set via Xaml Style. If the property has changed, I want to draw the lines. But Setters aren't called, if property is changed by xaml. Xaml calls SetValue() itself. But I need to know, when this property is changed to call my function for drawing the lines. If I call this function in the constructor, the property isn't bound yet. Can anyone help me please.
You can add PropertyChanged callback to your DependencyProperty declaration like
public static readonly DependencyProperty LineCountProperty = DependencyProperty.Register(
"LineCount",
typeof(int),
typeof(Window),
new FrameworkPropertyMetadata(
0,
new PropertyChangedCallback(OnLineCountChanged)
)
);
private static void OnLineCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//Here you call you function on `d` by typecasting it into your class
}

WPF Set Out of the Box Property to Inheritable

Is it possible to change the inheritance settings for a WPF property? Ideally, I would set ToolTipService.ShowDelay at the Window or UserControl level and everything in the visual tree would inherit from there. I know this is possible with a custom dependency property, but with the default properties?
You can't do this directly because you're working with an attached property. With a normal DP you can override the metadata on a specific (usually derived) type, but there's not really a place you can do this for an attached property because the metadata is declared on the owner (ToolTipService) but it's used on every other type by referencing that owner, and also the metadata it originally declared.
You can simulate the behavior you want by declaring your own version of the property and then using that to set the real one on each inheritor of that value. Here's the property declaration:
public static readonly DependencyProperty InitialShowDelayProperty = DependencyProperty.RegisterAttached(
"InitialShowDelay",
typeof(int),
typeof(MyWindow),
new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.Inherits, InitialShowDelayPropertyChanged));
public static int GetInitialShowDelay(DependencyObject target)
{
return (int)target.GetValue(InitialShowDelayProperty);
}
public static void SetInitialShowDelay(DependencyObject target, int value)
{
target.SetValue(InitialShowDelayProperty, value);
}
private static void InitialShowDelayPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ToolTipService.SetInitialShowDelay(d, (int)e.NewValue);
}
And then to set the inheriting value just set your new property and it should set ToolTipService's real one for you on all children:
local:MyWindow.InitialShowDelay="555"

Custom object as a DependencyProperty

I have a custom class, MyPerson. All (relevant) properties implement INotifyPropertyChanged.
I created a UserControl to display it, and it all worked fine. Binding to properties like MyPerson.FirstName (a string) all work - they display and update (two way binding) as expected.
Now I want to do more complex stuff in the codebehind, so I wanted to create a DependencyProperty with a PropertyType of MyPerson, but I'm not sure how to construct the DependencyProperty, in particular the PropertyChangedCallback part.
Can this be done? How so?
Read on this article - Custom Dependency Properties
Something like -
public static readonly DependencyProperty MyPersonValueProperty =
DependencyProperty.Register( "MyPersonValue", typeof(MyPerson),
typeof(MyPersonControl), new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPersonChanged) ) );
public MyPerson ThePerson
{
get { return (MyPerson)GetValue(MyPersonValueProperty); }
set { SetValue(MyPersonValueProperty, value); }
}
private static void OnPersonChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
// Property change code here
}

Binding public property in UserControl to property on parent does not work [duplicate]

I have a WPF UserControl project named FormattedTextBox that contains a TextBox and a WPF window project in the same solution.
My user control has two dependency properties registered like this:
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number",
typeof(double),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata());
public static readonly DependencyProperty NumberFormatStringProperty =
DependencyProperty.Register("NumberFormatString",
typeof(string),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata());
I make an instance of my usercontrol in the main window. The main window inplements INotifyPropertyChanged and has a property named MyNumber. In the XAML of the main window I try to bind to MyNumber like this:
Number="{Binding Path=MyNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
The binding doesn't work - I never get into the get or set on the Number property in the user control. Can anybody help?
When a dependency property is set in XAML (or by binding or animation etc.), WPF directly accesses the underlying DependencyObject and DependencyProperty without calling the CLR wrapper. See XAML Loading and Dependency Properties,
Implications for Custom Dependency Properties.
In order to get notified about changes of the Number property, you have to register a PropertyChangedCallback:
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number",
typeof(double),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata(NumberPropertyChanged));
private static void NumberPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var textBox = obj as FormattedTextBox;
...
}

WPF: Binding to readonly property in code

I'm currently doing some rescaling on data in a valueconverter whenever a panel is redrawn. I want to move some of this processing to the viewmodel as the most of the processing only occurs if the control size or a few other properties change.
To ensure the rescaled data looks acceptable I need the ActualWidth of the container in the viewmodel. I want to bind it to a property of the viewmodel one way so when it changes I can trigger the rescaling processing.
All the examples I could find bind a CLR or dependency property to an element rather than the other way and I'm clearly missing something in my understanding to work out how I should do it. I have have tried a few different things setting up the binding but am just not getting it right.
Any hints? thanks.
In MyView XAML:
<myItemsControl/>
In MyView code behind, something like:
Binding b = new Binding(MyWidthProperty);
b.Mode = BindingMode.OneWay;
b.Source = myItemsControl.Name;
.........?
and
public static readonly DependencyProperty MyWidthProperty =
DependencyProperty.Register( "MyWidth", typeof(Double), typeof(MyViewModel));
In MyViewModel:
public Double MyWidth{
get { return _myWidth; }
set { _myWidth = value; ViewChanged(this); } }
You cannot do it this way. You cannot set a Binding to ActualWidth, as it's read-only.
You can only set a binding to MyWidth. But for this, you need first to convert MyWidth into a DependencyProperty. Then you will be able to do something like
Binding b = new Binding("ActualWidth") { Source = myItemsControl };
this.SetBinding(MyViewModel.MyWidthProperty, b);
For converting into a dependency property, you'll need to replace your definition of MyWidth with the following:
public static readonly DependencyProperty MyWidthProperty =
DependencyProperty.Register("MyWidth", typeof(double), typeof(MyViewModel),
new UIPropertyMetadata(
0.0,
(d, e) =>
{
var self = (MyViewModel)d;
ViewChanged(self);
}));
But be careful with dependency properties; it's better to read the documentation first.
Edit: You would also need to define the property this way:
public double MyWidth
{
get { return (double)this.GetValue(MyWidthProperty); }
set { this.SetValue(MyWidthProperty, value); }
}

Resources