none
System.StackOverflowException и правило CA2227 (c#, WPF, VS 2010-2012) RRS feed

  • Вопрос

  • Здравствуйте.

    Собственно дилемма - если все работает, нарушается правило CA2227; есть правило соблюдать, выскакивает исключение System.StackOverflowException. Как быть? Очень хотелось бы соблюсти правило. Раньше такое удавалось, но тогда я не использовал INotifyPropertyChanged.

    НЕ СОБЛЮДЕНИЕ ПРАВИЛА:

    public class ImageItems : INotifyPropertyChanged
    {
        public ImageItems()
        {
            Items = new BindingList<ImageItem>();
        }
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        private BindingList<ImageItem> items;
    
        public BindingList<ImageItem> Items
        {
            get { return items; }
            set
            {
                items = value;
                NotifyPropertyChanged("Items");
            }
        }
    }

    ВЫСКАКИВАЕТ ИСКЛЮЧЕНИЕ:

    public class ImageItems : INotifyPropertyChanged
    {
        public ImageItems()
        {
            items = new BindingList<ImageItem>();
        }
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        private BindingList<ImageItem> items
        {
            get { return items; }
            set
            {
                items = value;
                NotifyPropertyChanged("items");
            }
        }
    
        public BindingList<ImageItem> Items { get { return items; } }
    }

    Подскажите, как быть?
    • Изменено Hovanskiy 17 марта 2013 г. 16:35
    17 марта 2013 г. 16:33

Ответы

  • Не совсем понятно зачем вы создаете класс который содержит в себе коллекцию таких же элементов?

    Что бы не появлялась ошибка достаточно поменять

    public class ImageItems : INotifyPropertyChanged { public ImageItems() { _item = new BindingList<ImageItem>(); } public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged;

    private BindingList<ImageItem> _item; public BindingList<ImageItem> Items { get { return _item; } } }


    • Изменено Brash_O 17 марта 2013 г. 17:28
    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 17:26
  •         private ObservableCollection<ImageItem> items;
    
            private void Initialize()
            {
                items = new ObservableCollection<ImageItem>();
                View = CollectionViewSource.GetDefaultView(items);
            }
    
            public ICollectionView View { get; private set; }
    
            public void AddNewImage(ImageItem imageItem)
            {
                if (items.Count(x => x.Path == imageItem.Path) == 0)
                    items.Add(imageItem);
            }

    Создаете private коллекцию. Во время запуска инициализируете ее и получаете для DefaultView (для привязки View к ListBox). И через public метод добавляете элементы в коллекцию, предварительно их проверив.

    Такой вариант вам подойдет?

    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 18:42
  •         private ObservableCollection<ImageItem> items;
    
            private void Initialize()
            {
                items = new ObservableCollection<ImageItem>();
                View = CollectionViewSource.GetDefaultView(items);
            }
    
            public ICollectionView View { get; private set; }
    
            public void AddNewImage(ImageItem imageItem)
            {
                if (items.Count(x => x.Path == imageItem.Path) == 0)
                    items.Add(imageItem);
            }

    Создаете private коллекцию. Во время запуска инициализируете ее и получаете для DefaultView (для привязки View к ListBox). И через public метод добавляете элементы в коллекцию, предварительно их проверив.

    Такой вариант вам подойдет?

    Не совсем понял такую реализацию.

    Я сделал так:

    private ObservableCollection<ImageItem> imageItems = new ObservableCollection<ImageItem>();
    
    public MainWindow()
    {
        InitializeComponent();
        /* ... */
        DataContext = imageItems;
    }
    
    public void AddItem(ImageItem item)
    {
        if (imageItems.Count(x => x.Path == item.Path) == 0)
            imageItems.Add(item);
    }
    
    <ListBox ItemsSource="{Binding IsAsync=True}">

    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 18:47

Все ответы

  • А зачем вам понадобилось предоставлять доступ к свойству Items (т.е. установки новой коллекции)? Это не очень удачно, можно попасть еще и на null... Чем вам не угодил метод Clear()?


    17 марта 2013 г. 17:10
  • А зачем вам понадобилось предоставлять доступ к свойству Items (т.е. установки новой коллекции)? Чем вам не угодил метод Clear()?


    Не совсем понял вас. Можно пример?
    17 марта 2013 г. 17:12
  • Вы разрабатываете для WPF или WindowsForms?
    17 марта 2013 г. 17:14
  • Вы разрабатываете для WPF или WindowsForms?

    WPF. В VS 2012.
    P.S. Затем я этот класс связываю с ListBox.

    DataContext = imageItems;
    
    ItemsSource="{Binding Items, IsAsync=True, Mode=OneWay}"

    • Изменено Hovanskiy 17 марта 2013 г. 17:17 Добавил
    17 марта 2013 г. 17:15
  • Не совсем понятно зачем вы создаете класс который содержит в себе коллекцию таких же элементов?

    Что бы не появлялась ошибка достаточно поменять

    public class ImageItems : INotifyPropertyChanged { public ImageItems() { _item = new BindingList<ImageItem>(); } public void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } } public event PropertyChangedEventHandler PropertyChanged;

    private BindingList<ImageItem> _item; public BindingList<ImageItem> Items { get { return _item; } } }


    • Изменено Brash_O 17 марта 2013 г. 17:28
    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 17:26
  • Не совсем понятно зачем вы создаете класс который содержит в себе коллекцию таких же элементов?

    Что бы не появлялась ошибка достаточно поменять

    public class ImageItems : INotifyPropertyChanged
    {
        public ImageItems()
        {
    ...

    Да. Действительно работает и без ошибки и с правилом. Но получается, что у меня теперь 3 одинаковых коллекции!?
    Т.е. проблема решает просто добавлением 3-ей коллекции "private BindingList<ImageItem> _item;" и работой от нее!?
    17 марта 2013 г. 17:33
  • Вы перемудрили. Для таких целей в WPF используется коллекция ObservableCollection.
    17 марта 2013 г. 17:38
  • А вот вы говорили:

    "А зачем вам понадобилось предоставлять доступ к свойству Items (т.е. установки новой коллекции)? Чем вам не угодил метод Clear()?",

    что вы имели ввиду? Можно глянуть на другую реализацию?

    P.S. Так как мне надо связать список с ListBox, приходится использовать "BindingList".

    P.S. #2
    Такой класс я реализовал исходя из этого:
    Обновление (перересовка) элементов (c#, WPF, VS 2010-2012)

    • Изменено Hovanskiy 17 марта 2013 г. 17:41
    17 марта 2013 г. 17:38
  • Дело в том, что если я делаю так:

    public class ImageItems : ObservableCollection<ImageItem>
        {
            public new void Add(ImageItem item)
            {
                if (this.Count > 0)
                    if (this.Count(x => x.Path == item.Path) == 0)
                        this.Add(item);
            }
        }
    
    public class ImageItem : INotifyPropertyChanged
    ...
    У меня ничего не добавляется!
    17 марта 2013 г. 17:52
  • А вы используйте так:

    public ObservableCollection<ImageItem> Items { get; private set; }

    ...

    Items = new ObservableCollection<ImageItem>();

    DataContext = Items;

    ...

    не надо наследовать от ObservableCollection, если вам не требуется какое-то своеобразное поведение.

    17 марта 2013 г. 18:06
  • Подскажите, пожалуйста, как можно реализовать защиту от добавления одинаковых элементов?

    Если я реализую так:

    public class ImageItems : ObservableCollection<ImageItem>
        {
            public new void Add(ImageItem item)
            {
                if (this.Count(x => x.Path == item.Path) == 0)
                    base.Add(item);
            }
        }

    то все работает.

    А как мне это реализовать, если делать так:

    private ObservableCollection<ImageItem> imageItems = new ObservableCollection<ImageItem>();
    
    /*
    Так я все время натыкаюсь на "Невозможно присвоить "Add" значение, поскольку он является "группа методов""
    */

    17 марта 2013 г. 18:21
  •         private ObservableCollection<ImageItem> items;
    
            private void Initialize()
            {
                items = new ObservableCollection<ImageItem>();
                View = CollectionViewSource.GetDefaultView(items);
            }
    
            public ICollectionView View { get; private set; }
    
            public void AddNewImage(ImageItem imageItem)
            {
                if (items.Count(x => x.Path == imageItem.Path) == 0)
                    items.Add(imageItem);
            }

    Создаете private коллекцию. Во время запуска инициализируете ее и получаете для DefaultView (для привязки View к ListBox). И через public метод добавляете элементы в коллекцию, предварительно их проверив.

    Такой вариант вам подойдет?

    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 18:42
  •         private ObservableCollection<ImageItem> items;
    
            private void Initialize()
            {
                items = new ObservableCollection<ImageItem>();
                View = CollectionViewSource.GetDefaultView(items);
            }
    
            public ICollectionView View { get; private set; }
    
            public void AddNewImage(ImageItem imageItem)
            {
                if (items.Count(x => x.Path == imageItem.Path) == 0)
                    items.Add(imageItem);
            }

    Создаете private коллекцию. Во время запуска инициализируете ее и получаете для DefaultView (для привязки View к ListBox). И через public метод добавляете элементы в коллекцию, предварительно их проверив.

    Такой вариант вам подойдет?

    Не совсем понял такую реализацию.

    Я сделал так:

    private ObservableCollection<ImageItem> imageItems = new ObservableCollection<ImageItem>();
    
    public MainWindow()
    {
        InitializeComponent();
        /* ... */
        DataContext = imageItems;
    }
    
    public void AddItem(ImageItem item)
    {
        if (imageItems.Count(x => x.Path == item.Path) == 0)
            imageItems.Add(item);
    }
    
    <ListBox ItemsSource="{Binding IsAsync=True}">

    • Помечено в качестве ответа Hovanskiy 17 марта 2013 г. 19:13
    17 марта 2013 г. 18:47
  • В принципе тоже самое. А так для себя посмотрите CollectionViewSource - полезная вещь.
    17 марта 2013 г. 18:52
  • В принципе тоже самое. А так для себя посмотрите CollectionViewSource - полезная вещь.

    Да, вещь возможно и была бы мне интересна, если бы я не переопределял ItemTemplate :)
    17 марта 2013 г. 19:28
  • ItemTemplate никак не связан с CollectionViewSource, первое это определение как отображать данные, второе где хранятся данные
    17 марта 2013 г. 20:04
  • ItemTemplate никак не связан с CollectionViewSource, первое это определение как отображать данные, второе где хранятся данные

    Возьмем пример из MSDN.

    Там показана сортировка списка и применение ее через DisplayMemberPath, а его нельзя применять вместе со стилизацией ItemTemplate. Делаю выводы - во всяком случае сейчас, мне это бесполезно ))

    17 марта 2013 г. 20:49
  • Согласен, но можно в ItemPemplate в биндингах указать какие поля объектов на каких элементах показывать и DisplayMemberPath больше не будет нужен.
    18 марта 2013 г. 5:54