Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do different instances have same dependency property value?

There is a serious problem when I try to develop a custom control in WPF/.NET 3.5.

Details

1.When I add two instance in the same Window,It appears that the 2nd one will always have the 1st one's dependency property value even though test2 are just be constructed without applying the template(e.g:tes2.TopItems/CenterItems/BottomItems are same with tes1's including Count,Items ...).

2.It will be ok when I remove any one of them.

3.The TopItems/CenterItems/BottomItems are initialized within OnApplyTemplate().

4.Changing the property "Calendar" and "CalendarViewType" will call the PropertyChangedCallBack().

5."TopItems","CenterItems","BttomItems" are used in {TemplateBinding} in the Control's Template.

6.I tried use "Normal Property" "{Binding RelativeSource=TemplatedParent}" instead of the "Depdendency Property" and {TemplateBinding},It worked well! !!!How weird!!!

Please,anyone can help?Thanks a looooooooooooooot!

Class Window

<Window>
 <Grid>
  <common:CalendarTitle x:Name="test1" Calendar="{Binding Calendar}" CalendarViewType="Month_Week"></common:CalendarTitle>
  <common:CalendarTitle x:Name="test2" Calendar="{Binding Calendar}"></common:CalendarTitle>
 </Grid>
</Window>

Class CalendarTile:Control

    public static readonly DependencyProperty CalendarProperty = DependencyProperty.Register("Calendar", typeof(ICalendar), typeof(CalendarTitle), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender, PropertyChangedCallback));
    public static readonly DependencyProperty CalendarViewTypeProperty = DependencyProperty.Register("CalendarViewType", typeof(CalendarViewType), typeof(CalendarTitle), new FrameworkPropertyMetadata(CalendarViewType.Week_Day, FrameworkPropertyMetadataOptions.AffectsRender, PropertyChangedCallback));
    public static readonly DependencyProperty TopItemsProperty = DependencyProperty.Register("TopItems", typeof(IEnumerable<ICalendarItem>), typeof(CalendarTitle), new FrameworkPropertyMetadata(new ObservableCollection<ICalendarItem>()));
    public static readonly DependencyProperty CenterItemsProperty = DependencyProperty.Register("CenterItems", typeof(IEnumerable<ICalendarItem>), typeof(CalendarTitle), new FrameworkPropertyMetadata(new ObservableCollection<ICalendarItem>()));
    public static readonly DependencyProperty BottomItemsProperty = DependencyProperty.Register("BottomItems", typeof(IEnumerable<ICalendarItem>), typeof(CalendarTitle), new FrameworkPropertyMetadata(new ObservableCollection<ICalendarItem>()));
    public IEnumerable<ICalendarItem> TopItems
    {
        get { return (IEnumerable<ICalendarItem>)GetValue(TopItemsProperty); }
        set { SetValue(TopItemsProperty, value); }
    }
    public IEnumerable<ICalendarItem> CenterItems
    {
        get { return (IEnumerable<ICalendarItem>)GetValue(CenterItemsProperty); }
        set { SetValue(CenterItemsProperty, value); }
    }
    public IEnumerable<ICalendarItem> BottomItems
    {
        get { return (IEnumerable<ICalendarItem>)GetValue(BottomItemsProperty); }
        set { SetValue(BottomItemsProperty, value); }
    }

PropertyCallBack()

 static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var calendarTile = (CalendarTitle)d;
        calendarTile.isLoaded = false;
        calendarTile.OnApplyTemplate();
    }

OnApplyTemplate()

 public override void OnApplyTemplate()
    {
        if (!isLoaded)
        {
            ClearItems();
            if (Calendar != null)
                PopulateItems();
            isLoaded = true;
        }
    }

PopulateItems()

 private void PopulateItems()
    {
        switch (CalendarViewType)
        {
            case CalendarViewType.Week_Day:
                {
                    foreach (var item in Calendar.Items)
                    {
                        if (item.Date.DayOfWeek == DayOfWeek.Sunday)
                            (TopItems as IList<ICalendarItem>).Add(item);
                    }
                    CenterItems = BottomItems = Calendar.Items;
                    break;
                }

            case CalendarViewType.Month_Week:
                {
                    foreach (var item in Calendar.Items)
                    {
                        if (item.Date.DayOfYear == 1)
                            (TopItems as IList<ICalendarItem>).Add(item);
                        if (item.Date.Day == 1)
                            (CenterItems as IList<ICalendarItem>).Add(item);
                        if (item.Date.DayOfWeek == DayOfWeek.Monday)
                            (BottomItems as IList<ICalendarItem>).Add(item);
                    }
                    break;
                }

            case CalendarViewType.Year_Month:
                {
                    foreach (var item in Calendar.Items)
                    {
                        if (item.Date.DayOfYear == 1)
                            (TopItems as IList<ICalendarItem>).Add(item);
                        if (item.Date.Day == 1)
                            (CenterItems as IList<ICalendarItem>).Add(item);
                        if (item.Date.DayOfWeek == DayOfWeek.Monday)
                            (BottomItems as IList<ICalendarItem>).Add(item);
                    }
                    break;
                }
        }

    }
like image 840
Claw Avatar asked Dec 09 '22 10:12

Claw


1 Answers

When you specify the default value of a dependency property, this default value is shared across all instances. So if it's a mutable reference type, like a collection, any change to this collection will be reflected across all instances of the class.

You should leave the default value to null, and initialize the collection in the class constructor instead. This way all instances of the class will have their own collection.

like image 183
Thomas Levesque Avatar answered Dec 11 '22 00:12

Thomas Levesque