0

I have a ObservationCollection in my CustomControl's class.

 public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof(ObservableCollection<Draggable>), typeof(Draggable), new PropertyMetadata(new ObservableCollection<Draggable>(), OnItemsChanged));

    private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
    {
        Draggable draggable = (Draggable)obj;

        if (e.NewValue != null)
        {
            if (((ObservableCollection<Draggable>)e.NewValue).Count > 0)
                draggable.HasItem = true;
            else
                draggable.HasItem = false;
        }
        else
        {
            draggable.Items = new ObservableCollection<Draggable>();
            draggable.HasItem = false;
        }
    }

and By default it has assigned by a new ObservableCollection<Draggable>.

I cant keep track of adding or removing the Items to/from this collection.

OnItemsChanged will fires whenever i assign a new ObservableCollection to this property. so Adding or removing the Items will not raise anything for me.

I have another property called HasItem. In my ControlTemplate i will show a Grid Whenever this property is True but it will never be True.

How can i solve this problem ?

EDIT:

My Main Class is Draggable and the ObservableCollection is the same in type. I have tried two solution:

  1. I have written a ValueConverter:

    [ValueConversion(typeof(ObservableCollection), typeof(Visibility))] public class IntToVisibilityConverter : IValueConverter { public static IntToVisibilityConverter Instance = new IntToVisibilityConverter();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        ObservableCollection<Draggable> Source = (ObservableCollection<Draggable>)value;
        if (Source.Count > 0)
            return Visibility.Visible;
        else
            return Visibility.Collapsed;
    }
    
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
    

    }

and i used it in this way:

 <Border x:Name="ItemsContainer" Visibility="{Binding Path=Items,Converter={x:Static MyConverters:IntToVisibilityConverter.Instance}}" ... >
  1. And I have written a constructor for my class and I added CollectionChanged event:

    public Draggable()
    {
        Items.CollectionChanged += Items_CollectionChanged;
    }
    
    private void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (Items.Count > 0)
            HasItem = true;
        else
            HasItem = false;
    }
    

both of them will throw in an Infinite Loop As VisualStudio Says. I can't Understand this because I cant see the loop it says.

RezaNoei2
  • 31
  • 5
  • As a note, it is a bug to set a non-null value as default value of a collection type (or any other reference type) dependency property. If there is more than one instance of your control, all would use the same collection object. – Clemens Sep 18 '18 at 05:31
  • See also [this answer](https://stackoverflow.com/a/15023687/1136211) for how to use IEnumerable instead of ObservableCollection, which provides greater flexibility. – Clemens Sep 18 '18 at 05:35
  • And out of curiosity, why is there RezaNoei2, when there already is [RezaNoei](https://stackoverflow.com/users/8890256/rezanoei)? If that is also you, what are you trying to achieve with a second account? – Clemens Sep 18 '18 at 06:11
  • @Clemens I have read the answer. there is some issue. ColumnsPropertyChanged will raise when a new IEnumerable assigned to the ColumnsPropertyChanged, and it must be a INotifyCollectionChanged. – RezaNoei2 Sep 18 '18 at 09:49
  • There is `var newCollection = e.NewValue as INotifyCollectionChanged`. When the result is not null, the `ColumnsCollectionChanged` handler is attached. – Clemens Sep 18 '18 at 09:52
  • Thanks for Answer. I have solved the problem by adding a Constructor to my Class. Now OnItemsChanged will fires at constructor and i have assigned a CollectionChanged Handler to it. – RezaNoei2 Sep 18 '18 at 10:27
  • 1
    and about me, I have out of question limit in SO. I tried to edit my previous questions and remove non-voted ones, but i have lost my privilege to ask question. I have begun to write an Enterprise application but i was beginner to WPF, I'm struggling on learning and I'm trying to respect to SO. – RezaNoei2 Sep 18 '18 at 10:29

2 Answers2

0

The only time you are setting HasItem is when you are setting the dependency property. I'm guessing you want it to recalculate that value when the collection's contents changes (e.g. by adding or removing items).

If you only need this from Xaml, then I wouldn't bother with the HasItem property: just bind the Visibility of the Grid to the Count property of the DP, using a ValueIsNotZeroConverter, which converts an int to a bool.

Richardissimo
  • 5,596
  • 2
  • 18
  • 36
  • Conversion thrown me to a Infinite loop. I have edited the question. I have solved the problem. thanks. – RezaNoei2 Sep 18 '18 at 10:31
0

OnItemsChanged will fires whenever property value changes(in case of ObservableCollection,if new value assign to the ObservableCollection property). For getting notification about the Adding or removing of the Items on ObservableCollection, we have to register CollectionChanged event of the ObservableCollection class. For example

private static void OnItemsChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            Draggable draggable = (Draggable)obj;

            if (e.NewValue != null)
            {
                if (((ObservableCollection<Draggable>)e.NewValue).Count > 0)
                {
                    draggable.HasItem = true;
                    (ObservableCollection<Draggable>)e.NewValue).CollectionChanged += CollectionChanged;
                }
                else
                    draggable.HasItem = false;
            }
            else
            {
                draggable.Items = new ObservableCollection<Draggable>();
                draggable.HasItem = false;
            }
        }
private void CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {

        }