I am trying to register an WPF attached property on a grid control, however, I met very strange behavior today:
public static class MyClass
{
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(string),
typeof(MyClass), null);
public static string GetMyProperty(DependencyObject d)
{
return (string)d.GetValue(MyPropertyProperty);
}
public static void SetMyProperty(DependencyObject d, string value)
{
d.SetValue(MyPropertyProperty, value); //<-- set breakpoint here
}
}
XAML:
<GridControl local:MyClass.MyProperty="My Name">
...
</GridControl>
when I wrote like this, the attached property's setter never gets executed. and value never be set. but I can snoop into the grid and found the attached property is attached with an empty value.
but when I change the attached property name to:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("xxxMyProperty", typeof(string),
typeof(MyClass), null);
i.e. use a different name other than MyProperty. then the breakpoint can be hit! and value can be set!
Moreover, when I change the attached property as:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(string),
typeof(UIElement), null);
i.e. change the owner type to UIElement, then I can also hit the breakpoint, just wondering why?
However, when I setup a binding in XAML instead of a string constant, each case above will got an exception saying A 'Binding' can only be set on a DependencyProperty of a DependencyObject
Binding XAML example:
<GridControl local:MyClass.MyProperty="{Binding MyStringValue}">
...
</GridControl>
Does anyone met this strange behavior before? What am I missing in my case? Thanks in advance for the reply!
If you are referring to the SetMyProperty method as the 'setter', then you should know that these methods are simply 'helper' methods for you to use. The Framework does not generally use these methods.
If however, you are saying that you would like to know when the value changes, then there is another way of doing this. Add a PropertyChangedCallback handler to the declaration of the property:
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(string), typeof(MyClass),
new UIPropertyMetadata(default(string.Empty), OnMyPropertyChanged));
public static void OnMyPropertyChanged(DependencyObject dependencyObject,
DependencyPropertyChangedEventArgs e)
{
string myPropertyValue = e.NewValue as string;
}
Related
I created a user control and wanted to get the value of the DependencyProperty "ListBoxReadOnly" in the code. I set the value in the XAML:
<control:AutoCompleteTextBox x:Name="actbFullName" ListBoxReadOnly="True"/>
When I tried to read the value in the constructor, it only shows the default value which is false.
I tried to get the value via a callback back but probably I am lacking some understanding of the whole framework. Since the callback is a static method, I cannot apply it to the instance of my user control.
public static readonly DependencyProperty ListBoxReadOnlyDependency =
DependencyProperty.Register("ListBoxReadOnly", typeof(bool),
typeof(AutoCompleteTextBox), FrameworkPropertyMetadata
(false, FrameworkPropertyMetadataOptions.AffectsRender));
public bool ListBoxReadOnly
{
get
{
return (bool) GetValue(ListBoxReadOnlyDependency);
}
set
{
SetValue(ListBoxReadOnlyDependency, value);
}
}
// constructor of user control
public AutoCompleteTextBox()
{
InitializeComponent();
// *** shows "false" (default value) even though set to true in XAML
// *** see XAML above ***
var test = ListBoxReadOnly;
}
Any help is appreciated :-)
I would expect your code (as is) to show false. The DP is initialized to false. In the constructor of your control, neither the default control style, nor the properties set in xaml have been applied yet.
The style is only applied after OnApplyTemplate() is called (unless you force it).
If you want to track DP changes, you need a DP change handler.
When I tried to read the value in the constructor, it only shows the default value which is false.
The property can't be set before the control has been initialized.
Since the callback is a static method, I cannot apply it to the instance of my user control.
You could cast the DependencyObject to the type of your control in the callback:
public static readonly DependencyProperty ListBoxReadOnlyDependency =
DependencyProperty.Register("ListBoxReadOnly", typeof(bool),
typeof(AutoCompleteTextBox), new FrameworkPropertyMetadata
(false, FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnChanged)));
private static void OnChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AutoCompleteTextBox ctrl = (AutoCompleteTextBox)d;
var x = ctrl.ListBoxReadOnly;
//...
}
Ok, so I'm trying to run some code that modifies a UI when a user changes a custom control's dependency property value in design mode; but only when in design mode.
I've tried these approaches:
1.
public static DependencyProperty x = ...Register(..., new PropertyMetadata(null, changeMethod));
2.
set { SetValue(XProp, value); changeMethod(value); }
3.
var observable = x as INotifyPropertyChanged;
observable.PropertyChanged += ObservablePropertyChanged;
But all of them seem to have their own issues in that they either trigger errors or don't work at all.
So does anyone know what the correct way to listen to a dependency property change in design mode is, and if so can you give an example?
The right way to handle DependencyProperty changes is to:
. Declare the DependencyProperty:
public static DependencyProperty MyXProperty;
. Create the public get/set Property:
public string MyX
{
get { return (string)GetValue(MyXProperty); } //Supposing that the property type is string
set { SetValue(MyXProperty, value); }
}
. Register the DependencyProperty in your static constructor:
static MyClass()
{
MyXProperty= DependencyProperty.Register("MyX", typeof(string), typeof(MyClass), new FrameworkPropertyMetadata("", OnMyXPropertyChanged));
}
. Declare the Property Changed Method:
private static void OnMyXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MyClass thisClass = d as MyClass ;
//Do Something
}
Please provide more information if you still can't find your solution.
this is the Code behind of user control
public delegate void YardSelectionChangedDelegate();
public event YardSelectionChangedDelegate YardSelectionChanged;
public static readonly DependencyProperty SelectedYardIdProperty =
DependencyProperty.Register(
"SelectedYardId",
typeof(long),
typeof(YardSelectorUserControl),
new UIPropertyMetadata(null));
And this is the Property:
public long SelectedYardId
{
get { return (long)GetValue(SelectedYardIdProperty); }
set { SetValue(SelectedYardIdProperty, value); }
}
And this is the Binding in the parent window:
SelectedYardId="{Binding Path=YardId,UpdateSourceTrigger=PropertyChanged}"
The problem is that the Set of the property never work and cursor never reach the Set body.
thanks indeed.
That is because binding engine doesn't use your set or get accessors for setting or getting a property. It uses SetValue and GetValue of the DependencyObject directly. In order to trigger an event while changing a dependency property you need to define a callback delegate while registering your dependency property like this:
public static readonly DependencyProperty SelectedYardIdProperty =
DependencyProperty.Register(
"SelectedYardId",
typeof(long),
typeof(YardSelectorUserControl),
new UIPropertyMetadata(OnSelectedYardIdChanged));
public static void OnSelectedYardIdChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
// Action
}
Maybe you should Implement INotifyPropertyChanged in your model, and change "YardId" property to raise PropertyChanged event in the "Set" body.
I have the following class schema
public Class Test : DependencyObject
{
private DependencyProperty _thickness = DependencyProperty.Register("Thickness", typeof(double), typeof(CounterDataStreamWrapper));
public double Thickness
{
get
{
return (double)GetValue(this._thickness);
}
set
{
SetValue(this._thickness, value);
}
}
... Rest of the code
}
Essentially I have a collection of Test objects, and I want to bind the Thickness value for each one to its corresponding UI element. I am not too familiar with C# binding. When I try to create multiple objects, I am running into "DependencyProperty is already registered" issue. I am sure that I am just missing some key concept for binding to DependencyProperty.
Any help is appreciated!
You are registering the Thickness DependencyProperty on the CounterDataStreamWrapper type and private per instance.
Make the DependencyProperty public static and register it for the class Test.
public static DependencyProperty Thickness =
DependencyProperty.Register("Thickness", typeof(double), typeof(Test));
It's supposed to be static. Like this:
private static DependencyProperty _thickness ...
I'm trying to develop a custom tri-state button user control and so far I've been using CTF to set properties.
But I would like to change this to be using the WPF property system with PropertiesDependencies.
Unfortunately I don't manage to make it work, when I set the property from my xaml (father) using a DynamicResource, the value is not set.
<common:StateImageButton x:Name="story_buttonRecord" BackTest="{DynamicResource backTest}" />
Here is the code I have in my button controller :
public ImageSource BackTest
{
get { return (ImageSource)this.GetValue(BackProp); }
set { this.SetValue(WidthProp,value); }
}
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata());
I don't even use the property in my button xaml yet, but it apparently doesn't even enter in the Setter. I've been searching a lot online without success. So maybe I'm missing something .
Thanks in advance for your help,
Boris
Also, WPF doesn't use the setter provided to set a property, it does it directly.
The way to debug when WPF sets a property is to add a callback for when the property is set, like so.
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata(OnBackChanged));
private static void OnBackChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var sender = (StateImageButton)d; // Put a breakpoint here
}