Skip to main content

Microsoft Silverlight

Answered Question Creating a Collection DependencyPropertyRSS Feed

(0)

sdether
sdether

Member

Member

74 points

30 Posts

Creating a Collection DependencyProperty

 I'm trying to create a DependencyProperty that supports this syntax:

<my:Foo>
  <my:Foo.Bars>
    <my:Bar .../>
    <my:Bar .../>
 </my:Foo.Bars>
</my:Foo>

instead of the more verbose syntax of:
 
<my:Foo>
  <my:Foo.Bars>
    <my:BarCollection>
      <my:Bar .../>
      <my:Bar .../>
    </my:BarCollection>
  </my:Foo.Bars>
</my:Foo>

I thought as long as my BarCollection class was a collection type, this would work. But that didn't work. I tried a number of things including setting the DependencyProperty type of PresentationFoundationCollection<Bar> but so far nothing seems to do the trick. Any suggestions?

 

thanks,
arne
 

tgrand
tgrand

Participant

Participant

788 points

173 Posts

Re: Creating a Collection DependencyProperty

I just did this recently using a class derived from ObservableCollection<T> as the type of my DependencyProperty.  The resulting XAML syntax is exactly like the first one you described.  The collection is even editable through GUI in Blend, which is really cool to see.

sdether
sdether

Member

Member

74 points

30 Posts

Re: Creating a Collection DependencyProperty

 I have my dependency set as such

         public static readonly DependencyProperty StatesProperty = DependencyProperty.Register(
            "States",
            typeof(ObservableCollection<FrameworkElement>),
            typeof(StateButton),
            new PropertyChangedCallback(StateButton.OnStateChanged)
            );

and the Xaml looks like this:

<my:StateButton x:Name="screen" Width="40" Height="40">
          <Path ...  />
          <Path ... />
              />
</my:StateButton>

 I also have the class decorated with [ContentProperty("States")]. This is what I get:

A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in System.Windows.dll

Additional information: StateButton does not support Path as content.

If i use my:StateButton.States to wrap the Paths, i get this instead:

 A first chance exception of type 'System.Windows.Markup.XamlParseException' occurred in System.Windows.dll

Additional information: AG_E_PARSER_BAD_PROPERTY_VALUE [Line: 20 Position: 22]


Any ideas?

tgrand
tgrand

Participant

Participant

788 points

173 Posts

Answered Question

Re: Creating a Collection DependencyProperty

I'm not sure what the problem is, but here's a description of what's working for me.  I have a control derived from Control with a dependency property with the same code you just posted, but instead of ObservableCollection<FrameworkElement> I have a class derived from ObservableCollection<MyItem>.  Also, MyItem is derived from ContentControl.  And MyItem is what I put in the XAML, inside a tag for the collection (matching the first syntax from your original post).

Apoco
Apoco

Member

Member

16 points

12 Posts

Re: Creating a Collection DependencyProperty

I am having the same issue as sdether.  As far as I can tell, I'm trying the same technique as tgrand.  Here's my parent control that I want to have child objects:

    public partial class TabControl : UserControl
    {
        public static readonly DependencyProperty TabPagesProperty = DependencyProperty.Register(
            "TabPages", typeof(TabPageCollection),
            typeof(TabControl),
            delegate(
                DependencyObject obj,
                DependencyPropertyChangedEventArgs args) { });

        public TabControl()
        {
            InitializeComponent();
        }

        public TabPageCollection TabPages
        {
            get { return GetValue(TabPagesProperty) as TabPageCollection; }
            set { SetValue(TabPagesProperty, value); }
        }
    }

TabPageCollection is simply defined as this:

 
     public class TabPageCollection : ObservableCollection<TabPage>
    {
    }

And TabPage is a simple ContentControl:

    public class TabPage : ContentControl
    {
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register(
            "Header", typeof(object), typeof(TabPage),
            delegate(
                DependencyObject obj,
                DependencyPropertyChangedEventArgs args) { });

        public object Header { get; set; }
    }

 

However, when I try to add items to the collection property, like this:

     <my:TabControl>
      <my:TabControl.TabPages>
        <my:TabPageCollection>
          <my:TabPage>
            <my:TabPage.Header>
              <TextBlock>Header 1</TextBlock>
            </my:TabPage.Header>
            <my:TabPage.Content>
              <TextBlock>Content 1</TextBlock>
            </my:TabPage.Content>
          </my:TabPage>
          <my:TabPage>
            <my:TabPage.Header>
              <TextBlock>Header 2</TextBlock>
            </my:TabPage.Header>
            <my:TabPage.Content>
              <TextBlock>Content 2</TextBlock>
            </my:TabPage.Content>
          </my:TabPage>
        </my:TabPageCollection>
      </my:TabControl.TabPages>
    </my:TabControl>

I get this XAML parse error:

TabPageCollection does not support TabPage as content.

 

tgrand, could you post your working code?  According to your description, it seems like you're doing exactly what I'm trying to do.

tgrand
tgrand

Participant

Participant

788 points

173 Posts

Re: Creating a Collection DependencyProperty

Ok, I tried to put together a minimal sample for you.  Note that I'm working with a custom control, not a user control.  Three source files are listed below.  If you take the first two and put them into a class library, then take the third one and put it into a test app that references the class library, then get it running, you should see three rectangles.  Hope this helps.

toolbar.cs

using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;

namespace SLContainerTest
{
    public class Toolbar : Control
    {
        public Toolbar()
        {
            Items = new ToolbarItemCollection();
        }

        public ToolbarItemCollection Items
        {
            get { return (ToolbarItemCollection)GetValue(ItemsProperty); }
            set { SetValue(ItemsProperty, value); }
        }
        public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
                "Items", typeof(ToolbarItemCollection), typeof(Toolbar), null);

        protected override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            Canvas ItemCanvas = (Canvas)GetTemplateChild("ItemCanvas");
            double x = 0;
            foreach (ToolbarItem item in Items)
            {
                item.SetValue(Canvas.LeftProperty, x);
                FrameworkElement content = item.Content as FrameworkElement;
                x += content.Width + content.Margin.Right;
                ItemCanvas.Children.Add(item);
            }
        }
    }

    public class ToolbarItem : ContentControl
    {
    }

    public class ToolbarItemCollection : ObservableCollection<ToolbarItem>
    {
    }
}

generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:SLContainerTest;assembly=SLContainerTest"
    >
    <Style TargetType="src:Toolbar">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="src:Toolbar">
                    <Canvas x:Name="ItemCanvas"
                            Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" >
                    </Canvas>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style TargetType="src:ToolbarItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="src:ToolbarItem">
                    <ContentPresenter
                      Content="{TemplateBinding Content}"
                      ContentTemplate="{TemplateBinding ContentTemplate}"
                      FontFamily="{TemplateBinding FontFamily}"
                      FontSize="{TemplateBinding FontSize}"
                      FontStretch="{TemplateBinding FontStretch}"
                      FontStyle="{TemplateBinding FontStyle}"
                      FontWeight="{TemplateBinding FontWeight}"
                      Foreground="{TemplateBinding Foreground}"
                      HorizontalAlignment="Left"
                      HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                      Padding="{TemplateBinding Padding}"
                      TextAlignment="{TemplateBinding TextAlignment}"
                      TextDecorations="{TemplateBinding TextDecorations}"
                      TextWrapping="{TemplateBinding TextWrapping}"
                      VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

Page.xaml

<UserControl x:Class="SLContainerTestApp.Page"
    xmlns="http://schemas.microsoft.com/client/2007"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:tb="clr-namespace:SLContainerTest;assembly=SLContainerTest"
    Width="400" Height="300">
    <Canvas x:Name="LayoutRoot" Background="White">
        <tb:Toolbar>
            <tb:Toolbar.Items>
                <tb:ToolbarItem>
                    <Rectangle Width="20" Height="20" Fill="Red" Margin="2 2 2 2"/>
                </tb:ToolbarItem>
                <tb:ToolbarItem>
                    <Rectangle Width="30" Height="20" Fill="Green" Margin="2 2 2 2"/>
                </tb:ToolbarItem>
                <tb:ToolbarItem>
                    <Rectangle Width="40" Height="20" Fill="Blue" Margin="2 2 2 2"/>
                </tb:ToolbarItem>
            </tb:Toolbar.Items>
        </tb:Toolbar>
    </Canvas>
</UserControl>
 

yogesh.kolpe
yogesh.k...

Member

Member

4 points

7 Posts

Re: Re: Creating a Collection DependencyProperty

Hi......tgrand nice post...it is really helpfull for me ....

But can u post the whole source code for the toolbar control. at least the two classes in toolbar.cs 1)ToolbarItem and 2)ToolbarItemCollection.

Thanks in advance..... 

tgrand
tgrand

Participant

Participant

788 points

173 Posts

Re: Re: Creating a Collection DependencyProperty

I'm afraid that is the complete source code.  This was only a minimal sample, not an excerpt from a fully functioning toolbar control.  The two classes you mentioned are functional as-is - they just rely on their base classes for everything.

You might find this control's source code useful - I think it's structured similarly to what I described in this thread:

http://pagebrooks.com/archive/2008/08/21/coolmenu-a-silverlight-menu-control.aspx

yogesh.kolpe
yogesh.k...

Member

Member

4 points

7 Posts

Re: Re: Re: Creating a Collection DependencyProperty

 Hi....tgrand for ur reply....

its really cool demo.....

its helps me lot....

once again thanks.......... 

  • Unanswered Question
  • Answered Question
  • Announcement
Microsoft Communities