How can I change the default value of an inherited dependency property? - wpf

How can I change the default value for an inherited dependency property? In our case, we've created a subclass of Control which by default has its Focusable set to 'true'. We want our subclass to have the default of 'false'.
What we've been doing is simply setting it to 'false' in the constructor, but if someone uses ClearValue, it goes back to the default, not the value set in the constructor.
Here's what I'm currently doing to achieve this (This is a test control with a DP of 'Foo' for an example.) I'm not a fan of the 'new' to hide the property although thanks to AddOwner, it does point to the same shared instance so I guess it's ok. It looks like it inherits all the other metadata values as well so that's good. Just wondering if this is correct?
public class TestControlBase : Control
{
public static readonly DependencyProperty FooProperty = DependencyProperty.Register(
"Foo",
typeof(int),
typeof(TestControlBase),
new FrameworkPropertyMetadata(4) // Original default value
);
public int Foo
{
get { return (int)GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
}
public class TestControl : TestControlBase
{
public static readonly new DependencyProperty FooProperty = TestControlBase.FooProperty.AddOwner(
typeof(TestControl),
new FrameworkPropertyMetadata(67) // New default for this subclass
);
}
Mark
UPDATE...
I think this is even better as it eliminates the 'new' call. You still access it via the FooProperty on the base class since this uses AddOwner. As such, it's technically the same one.
public class TestControl : TestControlBase
{
// Note this is private
private static readonly DependencyProperty AltFooProperty = TestControlBase.FooProperty.AddOwner(
typeof(TestControl),
new FrameworkPropertyMetadata(67) // New default for this subclass
);
}

The correct way to override a base class's property is:
static TestControl() {
FooProperty.OverrideMetadata(
typeof(TestControl),
new FrameworkPropertyMetadata(67)
);
}
EDIT:
AddOwner is meant to share the same DependencyProperty across types that are not related (i.e. the TextProperty of TextBox and TextBlock).

Related

Dependency property value is not inherited

I declared a dependency property with FrameworkPropertyMetadataOptions.Inherits:
public static class DesignerItemStyles {
public static readonly DependencyProperty HeaderBackgroundProperty =
DependencyProperty.RegisterAttached(
"HeaderBackground", typeof(Brush), typeof(DesignerItemStyles),
new FrameworkPropertyMetadata(
Brushes.DesignerViewElementHeaderBackground,
FrameworkPropertyMetadataOptions.Inherits));
/* Below are Get & Set as usual */
}
It kind of works, but somehow not throughout the visual tree. Here is a screenshot showing ContentPresenter that inherit value from HeaderedDesignerItemChrome:
And now, a screenshot showing content of the ContentPresenter, and it does not inherit the value. Nor it is set to something else - it is a default value:
Any idea why?
Using this is not that straight forward since there are some rules that need to be followed to implement property with inheritable values. Here they are:
On parent, dependency property must be defined as attached property. You can still declare property getter/setter, but property must be attached. Here is simple declaration:
public static readonly DependencyProperty InheritedValueProperty =
DependencyProperty.RegisterAttached("InheritedValue",
typeof(int), typeof(MyClass), new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
public static int GetInheritedValue(DependencyObject target)
{
return (int)target.GetValue(InheritedValueProperty);
}
public static void SetInheritedValue(DependencyObject target, int value)
{
target.SetValue(InheritedValueProperty, value);
}
public int InheritedValue
{
get
{
return GetTimeSlotDuration(this);
}
set
{
SetTimeSlotDuration(this, value);
}
}
Child objects would define their instance of the property with inherited value using AddOwner. Following is the code that goes into say MyChildClass sample class:
public static readonly DependencyProperty InheritedValueProperty;
public int InheritedValue
{
get
{
return (int)GetValue(InheritedValueProperty);
}
set
{
SetValue(InheritedValueProperty, value);
}
}
static MyChildClass()
{
InheritedValueProperty =
MyClass.InheritedValueProperty.AddOwner(typeof(MyChildClass),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.Inherits));
}
The global default value is preserved and inheritance still works, if the single argument overload is used...
MyClass.InheritedValueProperty.AddOwner(typeof(MyChildClass));
Note that property is in child class declared as standard dependency property and that it specifies Inherit in meta-data options.
With setup like this now when MyChildClass in parented to MyClass visually or logically they will share the same property value automatically.
So technically, what you see in the Visual Tree is doing what you told it to do. It set the default value that you told it to and the inherited controls inherit from the value of the parent which is your ContentPresenter
Eliminating one of the two ContentPresenters (visible on both screenshots just above DesignerItemsPresenter) worked for me. I am inclined to believe that was a bug in WPF framework itself.

How can I get databinding debug information in MVVM/Prism?

I am making my first serious foray into Prism(Unity). I have a module with a toolbar control that gets loaded (properly) into the region that it is supposed to. This toolbar is a listbox with ItemsSource databound to the ToolButtons property on its ViewModel, the constructor for which instantiates and adds three ToolButtons to the ToolButtons collection.
My ToolButton class has three custom DependencyProperties: Title (string), ButtonFace (Image), ActiveDocumentCount (int). Styling is taken care of by a resource dictionary in the module with a Style and associated ControlTemplate. I have databound the properties, but none of the values or the image are displaying (other elements in the style are however) via TemplateBinding.
I am trying to debug the databinding, but to no avail. I do not get any massages pertinent in the Output window, and the 2nd and 3rd suggestions in this blog have produced no output either. I think that if I could get the verbose (i.e. PresentationTraceSources.TraceLevel=High) output, I could figure out what is happening on the databinding front.
EDIT:
Toolbutton Class
public class ToolButton : Button
{
public ToolButton()
{
//DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolButton), new FrameworkPropertyMetadata(typeof(ToolButton)));
}
public Image ButtonFace
{
get { return (Image)this.GetValue(ButtonFaceProperty); }
set { this.SetValue(ButtonFaceProperty, value); }
}
public static readonly DependencyProperty ButtonFaceProperty =
DependencyProperty.Register("ButtonFace", typeof(Image), typeof(ToolButton), new PropertyMetadata(null));
public string Title
{
get { return (string)this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(ToolButton), new PropertyMetadata(""));
public int OpenRecordCount
{
get { return (int)this.GetValue(OpenRecordCountProperty); }
set { this.SetValue(OpenRecordCountProperty, value); }
}
public static readonly DependencyProperty OpenRecordCountProperty =
DependencyProperty.Register("OpenRecordCount", typeof(int), typeof(ToolButton), new PropertyMetadata(null));
}
Those DPs look ok SetValue in the CLR backed property is fine....but if you or anyone is setting a local value on those properites (e.g. by calling your CLR backed properties or DependencyObject.SetValue) then that will destroy the binding.
Related links:
http://arbel.net/2009/11/04/local-values-in-dependencyobjects/
http://blogs.msdn.com/b/vinsibal/archive/2009/05/21/the-control-local-values-bug-solution-and-new-wpf-4-0-related-apis.aspx
http://wpf.2000things.com/2010/12/06/147-use-setcurrentvalue-when-you-want-to-set-a-dependency-property-value-from-within-a-control/
Whats the difference between Dependency Property SetValue() & SetCurrentValue()

Is it possible to get x:Name of a DependencyObject (Silverlight)?

I have a DependencyObject (an Interactivity Behavior), and I'd like to get its x:Name (just get, not set) from code. Is it possible?
EDIT: Following AnthonyWJones's answer:
I've inserted the following code into my base behavior:
[EditorBrowsable(EditorBrowsableState.Never)]
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register("Name", typeof(string), typeof(BaseBehavior<T>), new PropertyMetadata(null));
I've given my behaviors x:Name, yet the Name property doesn't get filled.
If you want your Name property to be the same as the x:Name XAML name, then instead of implementing your own dependcy property, piggy-back on the existing one that is already registered. You can simply implement your name property as:
public string Name
{
get { return (string) base.GetValue(FrameworkElement.NameProperty); }
set { base.SetValue(FrameworkElement.NameProperty, value); }
}
If the class deriving from DependencyObject does not expose a Name property then you cannot determine the assigned x:Name. The x:Name value is store only in an internal object tree and there is no API to resolve value (the object) back to a key value (the name).
However if this is your own behaviour then simply add a Name dependency property to your behaviour. x:Name will assign is value to a Name property if present.
If this an existing behaviour you may be able to inherit from it to create a new class that has a Name property. Unfortunately some behaviours are sealed so you can't always do this.
You can create 'Name' AttachedProperty, and use NameAttachedProperty.GetName(DependencyObject)
Of course you will have to attach it to your element before using.
public static class NameAttachedProprty
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.RegisterAttached("Name", typeof (string), typeof (NameAttachedProprty), new PropertyMetadata(default(string)));
public static void SetName(DependencyObject element, string value)
{
element.SetValue(NameProperty, value);
}
public static string GetName(DependencyObject element)
{
return (string) element.GetValue(NameProperty);
}
}

Default value for the 'Options' property cannot be bound to a specific thread

I find that when I change a class from
public class MarkdownEditorOptions : ObservableObject
to
public class MarkdownEditorOptions : INotifyPropertyChanged, DependencyObject
as I wanted to use dependency properties, I get the error
Default value for the 'Options' property cannot be bound to a specific thread. ...\Views\ShellView.xaml
Options is declared as a dependency property on ShellViewModel
public MarkdownEditorOptions Options
{
get { return (MarkdownEditorOptions)GetValue(OptionsProperty); }
set { SetValue(OptionsProperty, value); }
}
public static readonly DependencyProperty OptionsProperty =
DependencyProperty.Register("Options", typeof(MarkdownEditorOptions), typeof(ShellViewModel), new UIPropertyMetadata(new MarkdownEditorOptions()));
whats wrong?
See these questions
Why Would a Dependency-Property Implementation Crash My Application When I Provide a Default Value?
Attached Property: 'System.TypeInitializationException' when setting default value
Your Dependency property is not thread safe, meaning that it doesn't inherit from System.Windows.Freezable.
Change DependencyObject to Freezable and it'll work since Freezable derives from DependencyObject.

Using dependency properties in wpf

I'm not quite sure if I've got the right grasp on this or not, what I've read seems to agree with what I'm trying to do, however It doesn't seem to be working.
If I add an additional owner to a dependency property of a class, whenever the orig class dp changes, the change should get propagated to the additional owner, correct?
What I have is a custom control, which I want to set a property on, and then on certain objects that are within the custom control data template inherit this property value.
public class Class1: DependencyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders {
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
static Class1(){
LongDayHeadersProperty = DependencyProperty.Register("LongDayHeaders", typeof(bool), typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
}
}
public class Class2: DependecyObject{
public static readonly DependencyProperty LongDayHeadersProperty;
public bool LongDayHeaders{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
static Class2(){
LongDayHeadersProperty = Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
}
}
But if I assign a DependencyPropertyDescriptor to both properties, it only fires for the Class1 and Class2 doesn't change.
Have I missed something in my understanding?
UPDATE
After some testing, I'm not even sure if my child control is considered a child control within the logical or visual tree. I think it is, but the lack of success leads me to believe otherwise.
There a many class2's which exist in an observable collection of class1. This, to me, makes them childs of class1? But even if I use RegisterAttach on class2, and set the property in class1, it doesn't seem to have any effect?
As MSDN states, the Inherits flag only works when you use RegisterAttached to create the property. You can still use the property syntax for the property.
Update
For clarity, here is how I would define the properties:
public class Class1 : FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
DependencyProperty.RegisterAttached("LongDayHeaders",
typeof(bool),
typeof(Class1),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.Inherits));
public bool LongDayHeaders
{
get { return (bool)GetValue(LongDayHeadersProperty); }
set { SetValue(LongDayHeadersProperty, value); }
}
}
public class Class2: FrameworkElement
{
public static readonly DependencyProperty LongDayHeadersProperty =
Class1.LongDayHeadersProperty.AddOwner(typeof(Class2));
public bool LongDayHeaders
{
get{ return(bool)GetValue(LongDayHeadersProperty); }
set{ SetValue(LongDayHeadersProperty, value); }
}
}
If you want your children to be logical children of your control, you need to call the AddLogicalChild. Also, you should expose them through the LogicalChildren property. I must also point out that both classes must derive from FrameworkElement or FrameworkContentElement, as the logical tree is only defined for these elements.
Since you are using an ObservableCollection, you would handle the collection changed events and Add/Remove the children depending on the change. Also, the LogicalChildren property can just return your collection's enumerator.
You are confusing DependencyProperties with Attached (Dependency) Properties.
A DP is for when a class wants bindable, stylable etc properties on itself. Just like .NET properties, they are scoped within their classes. You can register for a property changed event on individual objects, but not globally. TextBox.Text is an example of this. Note that Label.Text is unrelated to TextBox.Text.
An AP is for when a class wants to decorate another object with additional properties. The class that declares the AP is able to listen for property changed events on ALL instances of other objects that have this AP set. Canvas.Left is an example of this. Note that you always have to qualify this setter: <Label Text="Hi" Canvas.Left="50"/>

Resources