Dependency Property
-
Monday, July 10, 2006 12:40 AM
Howdy...
I am a little stumped... a little tired... a little stupid (probably)
I have created an object that has a dependencyproperty in it... all is well..
I create an instance of the object and do the business... no problems.
When I go to create another instance I get this exception:
System.ArgumentException was unhandled
Message="'HeaderContent_1' property was already registered by 'Scene1'."
Source="WindowsBase"
StackTrace:
at System.Windows.DependencyProperty.RegisterCommon(String name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
at System.Windows.DependencyProperty.Register(String name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
at System.Windows.DependencyProperty.Register(String name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata)
at CustomTreeVewItem.Scene1.InitialiseProperties() in C:\DEV_PRJ\DEV_WINFX\TreeStuff\CustomTreeVewItem\Scene1.xaml.cs:line 58
at CustomTreeVewItem.Scene1..ctor(String LabelContent_1, String LabelContent_2, Int32 ProgressMinValue, Int32 ProgressMaxValue, Int32 ProgressActualValue) in C:\DEV_PRJ\DEV_WINFX\TreeStuff\CustomTreeVewItem\Scene1.xaml.cs:line 34
at MyTreeSample.Scene1.AddItemClicked(Object sender, RoutedEventArgs e) in C:\DEV_PRJ\DEV_WINFX\TreeStuff\MyTreeSample\Scene1.xaml.cs:line 27
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Boolean isSingleParameter)
at System.Windows.Threading.Dispatcher.Invoke(DispatcherPriority priority, Delegate method, Object arg)
at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Threading.Dispatcher.Run()
at System.Windows.Application.RunInternal(Window window)
at System.Windows.Application.Run(Window window)
at System.Windows.Application.Run()
at MyTreeSample.MainApplication.Main() in C:\DEV_PRJ\DEV_WINFX\TreeStuff\MyTreeSample\obj\Debug\Application.g.cs:line 50
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()Now I understand why I am getting this error, but I can't figure out how to avoid it... It has to be something simple as I have put them in, in the past and had no problems...
Any suggestions anyone??? please...
Cheers in advance for your time.
All Replies
-
Monday, July 10, 2006 11:54 AMIs it possible that your DependencyProperty is not declared as static?
I mean:
public static readonly MyDependencyProperty = DependencyProperty.Register("MyDependency", typeof(string), typof(MyClass), ...
If your property is not declared as static, the property will be registered as "new" for each instance of the object and might cause something like this...
Let me know if this was the case, otherwise, we'll keep looking!!! -
Monday, July 10, 2006 11:58 AM
Howdy Marcus..
It is declared as static but not readonly as I need to assign to the property...
Cheers
-
Monday, July 10, 2006 12:07 PM
I was just thinking a little more about your post..
The object is a Treeview item, so it is going to get newed up over and over as a new item is needed for the tree...
The property resides in the object, so wouldn't it need to be New each time the Object is created?
This error is pointing to the fact that this type of object has been created before and the said property that was registered to the first object is now global...
I need the property to be scoped only to it's object...
I am slightly dazed and confused..
Cheers
-
Monday, July 10, 2006 12:12 PM
You should only need to assign it once, during static construction.
That's exactly what readonly means. It doesn't prevent assignment. It just means you can only assign during static construction.
If you're getting an error where you assign it, this suggests you're trying to assign it a value somewhere other than in your static constructor. (E.g. are you trying to assign it in your instance constructor?)
You should make sure it's initialized just once. The easiest way to do that is to do it in static construction. (Either using the initializer syntax shown by Marcus, or by putting the code into a static constructor.)
-
Monday, July 10, 2006 12:23 PM
Howdy..
This object is not designed as a static object... when the property is decalred without static it still generates the same error..
I don't want it as a static object, and I am assigning a value to the property at different periods during runtime so I don't want the readonly property.
I am using the Metadata to assign the default value of the property and so I would also need to remove the public accessor to this property if I wanted it to be readonly...
Are suggesting to me that any object that conatins a DP must be a static object? This is not what I understand to be the case.
Cheers for your help, I am sure we can nut this out quickly.
-
Monday, July 10, 2006 12:33 PM
"This object is not designed as a static object"
Fine, but that's not relevant. Your DependencyProperty field still needs to be static.
Look at any of the WPF control types. They all have declare static fields to hold their DependencyProperties, and yet these controls are not designed to be static objects either.
"Are suggesting to me that any object that conatins a DP must be a static object?"
No, I'm suggesting that any field that contains a DP must be a static field. The initialization of this field belongs in your type's static constructor. (Either in the form of an explicit static constructor, or in the form of a field initializer, as Marcus posted.)
I think you may have misunderstood how DependencyProperty works by the way. Even though you register it just once in your static constructor, each instance of your type can have a different value for that DependencyProperty. The DependencyProperty object acts like a name for the property, and does not hold the actual value. So you only need one static instance of each DependencyProperty for your whole type, even though each instance of your type might have a different value for that DependencyProperty
Once again, I repeat my question: where are you initializing the DP?
Even if there are a thousand instances of your type, the type must initialize its DP once and only once. So if you're trying to initialize it from anywhere other than the type's static constructor, you are doing the wrong thing.
The fact that you're getting an error if you mark the static field that contains your DP as readonly strongly suggests that you're initializing that field in the wrong place. So please tell us: where is the code that initializes your DependencyProperty?
-
Monday, July 10, 2006 12:40 PM
Howdy...
Iam initialising the DP in a method called from either the default or overloaded static constructor.
"I think you may have misunderstood how DependencyProperty works by the way"
I think you are right about that....
-
Monday, July 10, 2006 12:47 PM
"from either the default or overloaded static constructor"
Err... there's no such thing.
There is only one static constructor. You can't have overloaded static constructors because static constructors can't take parameters. So there's also no notion of a 'default' static constructor. Either you have a static constructor or you don't. There is no 'default' static constructor and you cannot have overloaded static constructors. So I'm afraid what you've written there can't be correct.
I'm guessing that what you've actually done is initialized it in your default or overloaded constructor. As opposed to your static constructor. If you are initializing it in a normal constructor (either default or overloaded) that would definitely cause the error you're seeing. This is why I'm guessing that this is what you've done.
However, if you could post the constructors in question, I could verify that for sure.
By the way, by far the easiest way to add a DependencyProperty-backed property to a class is to use the 'propdp' code snippet in Visual Studio. If you've installed the VS Extensions for WinFX/.NET 3.0 you'll have this code snippet. It generates exactly the code you need for a DP.
-
Monday, July 10, 2006 12:53 PM
Howdy..
Sorry for adding the word static to my description... Correction.. either the default or overloaded constructor...
Code is here now:
public partial class Scene1
{
public Scene1()
{
this.InitializeComponent();// Insert code required on object creation below this point.
this.InitialiseProperties();
}public Scene1(string LabelContent_1, string LabelContent_2,int ProgressMinValue,int ProgressMaxValue,int ProgressActualValue)
{
this.InitializeComponent();// Insert code required on object creation below this point.
this.InitialiseProperties();//Set our property from the value parsed as a parameter
this.HeaderContent_1 = LabelContent_1;
}//DP Properties
public static DependencyProperty HeaderProperty_1;private void InitialiseProperties()
{
PropertyChangedCallback HeaderItemChanged_1 = new PropertyChangedCallback(OnHeaderItemChanged_1);PropertyMetadata HeaderPropertyMetaData_1 = new PropertyMetadata("HeaderItem 1", HeaderItemChanged_1);
HeaderProperty_1 = DependencyProperty.Register("HeaderContent_1",
typeof(string),
typeof(Scene1),
HeaderPropertyMetaData_1);
}public void OnHeaderItemChanged_1(System.Windows.DependencyObject d, System.Windows.DependencyPropertyChangedEventArgs e)
{
this.lab_HeaderItem1.Content = this.HeaderContent_1;
}public string HeaderContent_1
{
get { return (string) base.GetValue(HeaderProperty_1); }
set { base.SetValue(HeaderProperty_1, value); }
}}
Thanks for the snippet info... been meaning to look for that this morning..
Cheers for all your help by the way Ian.
-
Monday, July 10, 2006 1:12 PM
You know I am looking at this and wondering why I have a callback method in place?...
I adding a static constructor and removing the callback.
Cheers
-
Monday, July 10, 2006 1:17 PM
Ok so I now have this working correctly with the static constructor in place.
When I look back through the code, I can see that I missunderstood the DP system as an object requirement.
Thanks a ton Ian and Marcus, for showing me the error of my ways.
Cheers

