Solved

Default of DependencyObject

Posted on 2010-09-15
13
634 Views
Last Modified: 2012-05-10
Dear Masters and Experts,

I'm using a CustomControl with a DependencyObject as DependencyProperty. But it seems to be impossible to set any DefaultValue in FrameworkPropertyMetadata because of an ArgumentException. Of course I could initialize the DependencyObject in the Constructor or anywhere else. But after reset this value is lost. Do You have any idea to solve this problem?

Here is an example which shows this problem:

namespace DependencyObjectDefault
{
    public class MyButton : Button
    {
        public static readonly DependencyProperty ColorSchemeProperty;
        static MyButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
            try
            {
                // any ColorScheme-default results in ArgumentException
                //ColorSchemeProperty = DependencyProperty.Register("ColorScheme", typeof(ColorScheme), typeof(MyButton), new FrameworkPropertyMetadata(new ColorScheme()));
               
                // registering without default is the only possibility
                ColorSchemeProperty = DependencyProperty.Register("ColorScheme", typeof(ColorScheme), typeof(MyButton), new FrameworkPropertyMetadata());
            }
            catch (Exception e)
            {
                MessageBox.Show("ColorScheme:" + e.Message);
            }
        }
        public ColorScheme ColorScheme
        {
            get { return (ColorScheme)GetValue(ColorSchemeProperty); }
            set { SetValue(ColorSchemeProperty, value); }
        }
    }
    public class ColorScheme : DependencyObject
    {
        public static readonly DependencyProperty Brush1Property;
        public static readonly DependencyProperty Brush2Property;
        static ColorScheme()
        {
            try
            {
                Brush1Property = DependencyProperty.Register("Brush1", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Blue));
                Brush2Property = DependencyProperty.Register("Brush2", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Red));
            }
            catch (Exception e)
            {
                MessageBox.Show("ColorScheme:" + e.Message);
            }

        }
        public Brush Brush1
        {
            get { return (Brush)GetValue(Brush1Property); }
            set { SetValue(Brush1Property, value); }
        }

        public Brush Brush2
        {
            get { return (Brush)GetValue(Brush2Property); }
            set { SetValue(Brush2Property, value); }
        }
    }
}

<Window x:Class="DependencyObjectDefault.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DependencyObjectDefault"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <ControlTemplate x:Key="MyButtonTemplate" TargetType="{x:Type local:MyButton}">
            <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                <Grid>
                    <Rectangle Width="80" Height="80" Margin="0" Fill="{Binding Path=ColorScheme.Brush1,RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Left" VerticalAlignment="Top"></Rectangle>
                    <Ellipse Width="80" Height="80" Margin="0" Fill="{Binding Path=ColorScheme.Brush2,RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Opacity="0.7"></Ellipse>
                </Grid>
            </Border>
        </ControlTemplate>
    </Window.Resources>
    <Grid>
        <local:MyButton Content="Button" Height="125" HorizontalAlignment="Left" Margin="106,93,0,0" x:Name="myButton1" VerticalAlignment="Top" Width="119" BorderThickness="2" BorderBrush="DarkGray" Template="{StaticResource MyButtonTemplate}" Background="AliceBlue"></local:MyButton>
    </Grid>
</Window>

0
Comment
Question by:Leonard_
  • 7
  • 6
13 Comments
 
LVL 29

Accepted Solution

by:
Gautham Janardhan earned 500 total points
ID: 33684048
inherit your ColourScheme from Freezable instead of Dependency Object and implement CreateInstabce as shown below. The you can set default values for the dependency property.
public class ColorScheme : Freezable
    {
        public static readonly DependencyProperty Brush1Property;
        public static readonly DependencyProperty Brush2Property;
        static ColorScheme()
        {
            try
            {
                Brush1Property = DependencyProperty.Register("Brush1", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Blue));
                Brush2Property = DependencyProperty.Register("Brush2", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Red));
            }
            catch (Exception e)
            {
                MessageBox.Show("ColorScheme:" + e.Message);
            }

        }
        public Brush Brush1
        {
            get { return (Brush)GetValue(Brush1Property); }
            set { SetValue(Brush1Property, value); }
        }

        public Brush Brush2
        {
            get { return (Brush)GetValue(Brush2Property); }
            set { SetValue(Brush2Property, value); }
        }

        protected override Freezable CreateInstanceCore()
        {
            return new ColorScheme();
        }
    }

Open in new window

0
 

Author Comment

by:Leonard_
ID: 33685239
Hello gauthampj,

thank you for this idea. I have to make a few tests in my much more complex application. In the example there is just the problem that after reset the sub-properties are not updated in the property-window and couldn't be changed anymore until MyButton is deselected an then selected again.

Has the default value passed to FrameworkPropertyMetadata to be same as the return value of CreateInstanceCore?

0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33688670
no not necessarily. This will come into play only when your property has properties other than Dependency propery
0
Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

 

Author Comment

by:Leonard_
ID: 33690251
In my application I have to change the properties dynamically, but this is not possible because they are write-protected, the ColorScheme-Object is frozen. The Microsoft-Documentation tells me, that freezable objects remain unfrozen unless you explicitly freeze them. But I don't freeze the ColorScheme-Object. Is this done automatically? How can I prevent this?
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33693733
i don't think we can unfreeze them.. They are freezed by the runtime when the control comes into view. Instead of setting the properties of the default property it's better to reset the dependency property again with the new values...
0
 

Author Comment

by:Leonard_
ID: 33694386
I forgot to say that in my application the dynamical changes are made at designtime in a CategoryEditor, so it seems that ColorScheme-object is already frozen at designtime.

Besides I have still the problem mentioned in my first comment: after reset the sub-properties are not updated in the property-window and couldn't be changed anymore until MyButton is deselected an then selected again. After the property-window is updated this way and changing the brush by the slider in the brush-editor the brush-editor is closed immediately after a minimal change. Doing this a second time the brush could be changed this way. But the corresponding xaml-entry again didn't take place until deselecting MyButton. Could You reproduce this behavior? I'm using Visual Studio 2010.

I think Freezable is good to give a defaultvalue, but the frozen-state (if it couldn't be prevented) has some disadvantages after reset.
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33703886
i had tried to reproduce your scenario (but in VS2008) .. trying to attach the code here....
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33703925
button code
public class ButtonWithDesignTime : Button
    {
        public static readonly DependencyProperty ColorSchemeProperty;
        static ButtonWithDesignTime()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ButtonWithDesignTime), new FrameworkPropertyMetadata(typeof(ButtonWithDesignTime)));
            try
            {
                // any ColorScheme-default results in ArgumentException
                //ColorSchemeProperty = DependencyProperty.Register("ColorScheme", typeof(ColorScheme), typeof(MyButton), new FrameworkPropertyMetadata(new ColorScheme()));

                // registering without default is the only possibility
                ColorSchemeProperty = DependencyProperty.Register("ColorScheme", typeof(ColorScheme), typeof(ButtonWithDesignTime), new FrameworkPropertyMetadata());
            }
            catch (Exception e)
            {
                MessageBox.Show("ColorScheme:" + e.Message);
            }
        }

        public ButtonWithDesignTime()
        {
            if (DesignerProperties.GetIsInDesignMode(this))
            {
                Content = "I'm in design mode";
            }
        }

        public ColorScheme ColorScheme
        {
            get { return (ColorScheme)GetValue(ColorSchemeProperty); }
            set { SetValue(ColorSchemeProperty, value); }
        }
    }

    public class ColorScheme : Freezable
    {
        public static readonly DependencyProperty Brush1Property;
        public static readonly DependencyProperty Brush2Property;
        static ColorScheme()
        {
            try
            {
                Brush1Property = DependencyProperty.Register("Brush1", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Blue));
                Brush2Property = DependencyProperty.Register("Brush2", typeof(Brush), typeof(ColorScheme), new FrameworkPropertyMetadata(Brushes.Red));
            }
            catch (Exception e)
            {
                MessageBox.Show("ColorScheme:" + e.Message);
            }

        }
        public Brush Brush1
        {
            get { return (Brush)GetValue(Brush1Property); }
            set { SetValue(Brush1Property, value); }
        }

        public Brush Brush2
        {
            get { return (Brush)GetValue(Brush2Property); }
            set { SetValue(Brush2Property, value); }
        }

        protected override Freezable CreateInstanceCore()
        {
            return new ColorScheme();
        }
    }

Open in new window

0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33703939
metadata file

.. this code is working as expected...the changes made in the property editor are reflecting in the xaml
internal class Metadata : IRegisterMetadata {

        // Called by Cider to register any design-time metadata
        public void Register() {
            AttributeTableBuilder builder = new AttributeTableBuilder();

            // Adorners
            builder.AddCustomAttributes(typeof(ButtonWithDesignTime), new FeatureAttribute(typeof(OpacitySliderAdornerProvider)));
            builder.AddCustomAttributes(typeof(ButtonWithDesignTime), new FeatureAttribute(typeof(PopupButtonAdornerProvider)));

            // MenuActions
            builder.AddCustomAttributes(typeof(ButtonWithDesignTime), new FeatureAttribute(typeof(CustomContextMenuProvider)));
            MetadataStore.AddAttributeTable(builder.CreateTable());
        }
    }

Open in new window

0
 

Author Comment

by:Leonard_
ID: 33707474
I'm sorry, I'm a little bit confused about the Metadata and the differences between VS 2008 and VS 2010. I'm using Metadata implementing Microsoft.Windows.Design.Metadata.IProvideAttributeTable. MetadataStore and IRegisterMetadata are only available in VS 2008. I'll try to translate your code to VS 2010.

But what about the types passed to FeatureAttribute? I found a similar example only in VS 2008. Besides the Brush-Editor is complete different in VS 2010 and it's color-sliders are already build-in.
0
 
LVL 29

Expert Comment

by:Gautham Janardhan
ID: 33707736
sorry i wont be able to test this in 2010 at this moment. What ever i'm are passing to the feature attributes you need to replace it with your designer.Please try to convert it into vs2010 and let me know hos it goes
0
 

Author Comment

by:Leonard_
ID: 33742140
I had no success with the feature attributes. But I think the problem in the Brush-Editor is not a problem of Freezable as the same behavior after reset occurs if ColorScheme implements INotifyPropertyChanged (which also allows a default-value). If there is no corresponding xaml-entry of the ColorSchemeObject (after reset) it is not possible to change the Brush with the slider. But I accept Freezable as solution to register a default-value of a DependencyObject.
0
 

Author Closing Comment

by:Leonard_
ID: 33742176
Problems in Visual Studio 2010 after reset:

The sub-properties are not updated in the property -window.

It is not possible to use the Brush-slider as it is immediately closed after a minimal change.
0

Featured Post

Master Your Team's Linux and Cloud Stack!

The average business loses $13.5M per year to ineffective training (per 1,000 employees). Keep ahead of the competition and combine in-person quality with online cost and flexibility by training with Linux Academy.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

832 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question