Public vs Private AttachedProperties - wpf

Where does it make sense to have AttachedProperties as private vs public?
Usually it is define as (example):
public static readonly DependencyProperty CommandProperty =
DependencyProperty.RegisterAttached(
"Command",
typeof(ICommand),
typeof(Click),
new PropertyMetadata(OnSetCommandCallback));
But I have also seen examples where some properties are private static readonly...
What are the consequences if I change the above CommandProperty to private now? It seems to be still available in my XAML intellisense if I do that. What am I missing here?

The difference is that you won't be able to access the DependencyProperty from outside of the class. This can make sense if the static Get and Set methods are private as well, (in an attached behavior where you need to store some behavior local data for example) but not otherwise (and I don't think I've ever seen this with public Get and Set).
An example of when you want to use the DependencyProperty is DependencyPropertyDescriptor. With a public DependencyProperty you can do the following
DependencyPropertyDescriptor de =
DependencyPropertyDescriptor.FromProperty(Click.CommandProperty, typeof(Button));
de.AddValueChanged(button1, delegate(object sender, EventArgs e)
{
// Some logic..
});
But if the DependencyProperty is private, the above code won't work.
However, the following will work fine for both a public and private DependencyProperty (if the static Get and Set methods are public) since the owner class can access the private DependencyProperty. This also goes for Bindings and values set through Xaml where GetValue and SetValue are called directly.
Click.SetCommand(button, ApplicationCommands.Close);
ICommand command = Click.GetCommand(button);
If you look through the framework you will notice that all of the public attached properties have a public DependencyProperty, for example Grid.RowProperty and Storyboard.TargetNameProperty. So if the attached property is public, use a public DependencyProperty

Related

When I encapulate a group of DependencyProperties into a DependencyObject, will property changes automatically be forwarded to UserControl?

I created a WPF UserControl with a number of DependencyProperty custom properties, which all affect OnMeasure and call PropertyChangedCallback, e.g.:
private static readonly DependencyProperty ArrowStrokeThicknessProperty = DependencyProperty.Register("ArrowStrokeThickness", typeof(double), typeof(ProjectListTreePanel), new FrameworkPropertyMetadata(2d, FrameworkPropertyMetadataOptions.AffectsMeasure, PropertyChangedCallback), ValidateArrowStrokeThickness);
I'd rather put all these properties into a separate DependencyObject:
internal class MyArrowProperties : DependencyObject
{
private static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register("StrokeThickness", typeof(double), typeof(MyArrowProperties), new FrameworkPropertyMetadata(2d, FrameworkPropertyMetadataOptions.AffectsMeasure, PropertyChangedCallback), ValidateStrokeThickness);
...
}
... and have that DependencyObject become a DependencyProperty of my UserControl:
public partial class ProjectListTreePanel : UserControl
{
private static readonly DependencyProperty ArrowProperty = DependencyProperty.Register("Arrow", typeof(MyArrowProperties), typeof(ProjectListTreePanel), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsMeasure, PropertyChangedCallback));
Will changes to the properties of the MyArrowProperties DependencyObject be automatically forwarded to the containing ProjectListTreePanel UserControl, so MeasureOverride is getting called on the ProjectListTreePanel UserControl, when, for instance, I update
MyProjectListTreePanel.Arrow.StrokeThickness = 2
?
Or what do I need to do to have changes of encapsulated properties be forwarded to outer containers?
Similarity
The problem described here is similar to the Thickness struct. The Thickness struct is a collection of four distinct values. When any of these values changes, the Thickness struct raises an OnPropertyChanged event.

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;
...
}

DependencyProperty PropertyChangedCallback vs placing code directly into the setter

Was just wondering about DependencyProperties.
Usually I'm seeing this kind of coding standard when executing some code after a DependencyProperty has changed.
public int SomeProperty
{
get { return (int)GetValue(SomePropertyProperty); }
set { SetValue(SomePropertyProperty, value); }
}
public static readonly DependencyProperty SomePropertyProperty =
DependencyProperty.Register("SomeProperty", typeof(int), typeof(MainWindow), new UIPropertyMetadata(new DependencyPropertyChangedEventHandler(OnSomePropertyChanged)));
private static void OnSomePropertyChanged(object obj, DependencyPropertyChangedEventArgs e)
{
//Some logic in here
}
But I don't think I've never seen this kind of implementation -
public int SomeProperty
{
get { return (int)GetValue(SomePropertyProperty); }
set
{
SetValue(SomePropertyProperty, value);
//Execute code in here
}
}
public static readonly DependencyProperty SomePropertyProperty =
DependencyProperty.Register("SomeProperty", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0));
Is this considered a bad practice?
Thanks!
This isn't just bad practice, this will actually result in incorrect behavior. When binding to dependency properties in XAML, the SetValue method will be called directly, not the setter. Basically, you can't guarantee that code there will even be executed.
Source: http://www.switchonthecode.com/tutorials/wpf-tutorial-introduction-to-dependency-properties
A little bit of a side note here - don't ever put anything but the
GetValue and SetValue calls inside the property wrapper. This is
because you never know if someone will set the property through the
wrapper, or straight through a SetValue call - so you don't want to
put any extra logic in the property wrapper. For example, when you set
the value of a dependency property in XAML, it will not use the
property wrapper - it will hit the SetValue call directly, bypassing
anything that you happened to put in the property wrapper.

Dependency property callback does not work

I have the following code:
private static readonly DependencyProperty IDProperty = DependencyProperty.Register(
"ID", typeof(int), typeof(DetailDataControl), new PropertyMetadata(-1, new PropertyChangedCallback(IDChanged)));
public int ID
{
get { return (int)GetValue(IDProperty); }
set { SetValue(IDProperty, value); }
}
private static void IDChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Do something here!
}
I can see that when I change ID, the line SetValue(IPproperty is called), but it doesn't call the IDChanged.
Why?
Your code is correct, however PropertyChanged callback will not be called until it has changed. Try changing the property to two different values in consecutive lines of code and have a break point you can see that it's been hit. I believe it's set to -1 and hence it isn't called.
Make the DP public static readonly. When setting the value in XAML, the wrapper is not used, the DP is used directly. So, it has to be public.
But...apparently you are setting it from within code? In that case, i don't know what's wrong...but you can always try.
I don't know if this was ever solved or not but if you are setting the value in the XAML file that uses it, there are certain circumstances where the proceedural code default value will take precedent and it will never fire from being set in the XAML initially. So remove the default value of -1 so
private static readonly DependencyProperty IDProperty = DependencyProperty.Register(
"ID", typeof(int), typeof(DetailDataControl), new PropertyMetadata(-1, new PropertyChangedCallback(IDChanged)));
becomes
private static readonly DependencyProperty IDProperty = DependencyProperty.Register(
"ID", typeof(int), typeof(DetailDataControl), new PropertyMetadata( new PropertyChangedCallback(IDChanged)));

Resources