Привязка TreeView HierarchicalDataTemplate ItemsSource к себе без пути к свойствуC#

Место общения программистов C#
Anonymous
Привязка TreeView HierarchicalDataTemplate ItemsSource к себе без пути к свойству

Сообщение Anonymous »

У меня есть собственный класс модели, реализующий IList, IList, ICollection, ICollection, IEnumerable и IEnumerable, который я хочу использовать в качестве DataType в HierarchicalDataTemplate для TreeView. Пользовательская коллекция использует базовую/внутреннюю ObservableCollection для управления элементами, а реализованные интерфейсы должны предоставлять элементы точно так же, как ObservableCollection.
Загвоздка в том, что Я не хочу, чтобы эта пользовательская коллекция имела свойство 'Item' или 'Children', чтобы кто-нибудь мог случайно вызвать Add(item) или Remove(item) -подобные методы для этих обычно открытых свойств. Что я хочу сделать в XAML: Вопрос: Может ли кто-нибудь указать, чего не хватает моей пользовательской универсальной коллекции(ям) для самоссылки в качестве ItemsSource HierarchicalDataTemplate без необходимости открытого свойства для дочерних узлов. Да, я не очень хорошо знаком с WPF, но это кажется возможным, должен быть способ. Или я пытаюсь достичь чего-то невозможного/не в рамках реализации, и поэтому должен предоставить свойство обычным способом?

Детали реализации на данный момент (предоставлены для того, чтобы дать контекст того, с какой реализацией мы имеем дело):
Ниже приведено краткое описание модели классов, некоторые из которых представляют собой коллекции сами по себе, созданные таким образом с целью прямой ссылки сами в XAML, а не один из членов их общедоступной собственности в качестве узла подэлементов. Все происходит от общих абстрактных классов со множеством защищенных виртуальных методов (это требование):

Код: Выделить всё

// Hierarchy
// System.Object
// ∟ class NotifyPropertyChangedBase : INotifyPropertyChanged
//   ∟ class ItemModel
//     ∟ class VisualItemModel
//       ∟ class VisualCollectionModel
//         ∟ class VisualCollectionModel
//           ∟ class HierarchicalCollectionModel
//             ∟ class SomeFinalUsableClass

public abstract class ItemModel: NotifyPropertyChangedBase {
public bool IsSelected { get; set; }
public bool IsVisible { get; set; }
public virtual void ItemAddedToCollection(ItemModel collection) { ... }
}

public abstract class VisualItemModel: ItemModel {
public bool IsExpanded { get; set; }
}

public abstract class VisualCollectionModel :
VisualItemModel,
IList, ICollection, IList, ICollection,
IEnumerable, IEnumerable
where TItem : VisualItemModel {

// This is the internal collection
protecte ObservableCollection ItemsCollection {
get { ...  }
}

object IList.this[int index] {
get {...}
set {...}
}
public TItem this[int index] {
get {...}
set {...}
}

protected virtual Int32 AddItemDirect(TItem item) {
ItemsCollection.Add(item);
return ItemsCollection.Count - 1;
}

public Int32 Add(TItem item) {
return AddItemDirect(item); // Call overridable method...
}
public Int32 Add(object obj) {
if (obj == null) return -1;
var item = obj as TItem;
return AddItemDirect(item); // Call overridable method...
}
bool IList.Contains(object obj) { ... }
bool ICollection.Contains(TItem item) { ... }
// ^^ all interface members are implemented
}

public abstract class HierarchicalCollectionModel
where TClass : VisualItemModel
where where TParent : VisualCollectionModel
where where TItem : VisualItemModel {

TParent Parent { get...; } // To have access to ancestors

protected override void ItemAdded(TItem item) { ... }
public override void ItemAddedToCollection(ItemModel collection) {
var parent = collection as TParent;
if (parent != null) SetParent(parent, true);
base.ItemAddedToCollection(collection);
}
}

// then a final class would derive from HierarchicalCollectionModel
Абстрактные базовые классы намного сложнее, поскольку они задают основу для потенциального использования в большинстве случаев. Вот, например, класс FileSystemItem, один из многих подобных только для всего приложения:

Код: Выделить всё

// Implementation for a single item type in TreeView
public class FileSystemItem :
HierarchicalCollectionModel,
IComparable {

protected override Int32 AddItemDirect(TItem item) {
ItemsCollection.InsertSorted(item);
// InsertSorted is a custom generic extension method
// to INSERT the IComparable TItem at the correct position in collection;
// that's why ObservableCollection.Add() is to never be accessed directly
}
protected override void BeforeParentChanged(
FileSystemItem oldParent, FileSystemItem newParent) {
// inform child items their ancestor has vanished...
// inform ancestors they have lost one descendant...
}
protected override void ProcessIsExpandedStateChanged(bool newState) {
if (newState) SetIcon16(SelectedDirectoryIcon16, true);
else SetIcon16(DirectoryIcon16, true);
base.ProcessIsExpandedStateChanged(newState);
}
}
или набор элементов, отсортированных по дате:

Код: Выделить всё

// Derived classes for any amount of different types in TreeView,
// yet, strongly constrained alltogether

public class RootNodeItem :
HierarchicalCollectionModel,
IComparable {
}

public class YearNodeItem :
HierarchicalCollectionModel,
IComparable {
public Int32 Year { get; set; }
}

public class MonthNodeItem :
HierarchicalCollectionModel,
IComparable {
public byte Month { get; set; }
}

public class DayNodeItem :
HierarchicalCollectionModel,
IComparable {
public byte Day { get; set; }
}

public class EntryItem: VisualItem, IComparable {
// ...
}
Все классы/модели, включая классы абстрактных коллекций, являются производными от ItemModel или VisualItemModel, которые по сути уже предоставляют всю модель данных TreeViewItem, необходимую для привязки.
Когда я раскрываю ObservableCollection в производных классах, все работает отлично, вот так:

Код: Выделить всё

public class FileSystemItem :
HierarchicalCollectionModel,
IComparable {

public ObservabeCollection Items {
// The property member I reference in binding,
// with appropriate PropertyChanged implementation
// that fires just perfect for every cases (add/remove/insert/clear...)
return ItemsCollection; // this is the underlying collection.
}
}
Но такой подход позволяет потребителям сделать это:

Код: Выделить всё

SomeFileSystemItem.Items.Add(someItemOutOfTheBlue);
Зачем все усложнять?
Это обходит все необходимые проверки, правильное положение вставки в коллекцию (

Код: Выделить всё

IComparable
), дублирование существования и обработки, даже некоторые элементы из ДРУГОГО TreeView, которые НИКОГДА не должны вторгаться в соседний TreeView, а также многие другие требования, которые слишком долго подробно описывать здесь.
Я знаю, что могу отсортировать коллекцию после добавления элементов и выполнить соответствующие проверки после добавления любого лямбда-элемента, НО я имею дело с несколькими типами данных, которые поступают по сотням элементов на узел, большинство из них обновляются в вопрос секунд: это действующий пул ожидающих элементов, обработанных элементов, входящих элементов, наиболее отсортированных по дате для всей задачи обновления архива на протяжении двух десятилетий данных, в то время как новые обновления появляются в реальном времени, источниками которых являются различные типы файлов/архивов, записанные аудиовызовы, десять тысяч на локальном жестком диске и, возможно, миллион через локальную сеть, в то время как сеть постоянно подает потоки новых данных, которые могут быть связаны со старыми данными, когда они обновляются.
Я тот, кто закладывает основу специального приложения чтобы легко группировать и отображать эти архивы для прямого манипулирования, не опасаясь потери данных и иерархии. Я не тот, кто на самом деле определяет, как эти данные должны быть нормализованы/обновлены/сериализованы; таким образом, конечный пользователь будет иметь доступ к большинству классов и к этому заманчивому свойству «Item» или «Children», которое сделает его/ее работу настолько простой; вместо этого это, скорее всего, повредит все данные (например, недействительные/сломанные '', приведет к взрыву всего архива...)
Вот почему важно, чтобы я никогда не предоставлял прямой доступ к базовой коллекции, в противном случае альтернативой является перехват непосредственно добавленного элемента, обнаружение того, что он не прошел надлежащие проверки, такие как принадлежность к соответствующему TreeView, удаление его из коллекции, а затем добавление его снова правильным способом, возможно, в виде клона. В процессе это приведет к увеличению количества PropertyChanged...
^^ Да, это крайний случай 0,001%, с которым никто не хочет иметь дело; Я тоже! но у меня заканчиваются варианты, так как я не понимаю, почему в TreeView отображается корневой узел моей коллекции, а не его элементы. TreeView ItemsSource — самый верхний элемент, он отображается. Но HierarchicalDataTemplate ItemsSource, похоже, не действует как коллекция с перечисляемыми элементами при ссылке на себя, вместо этого мне приходится предоставлять базовую коллекцию как свойство и указывать Path=Items в привязке.

Подробнее: https://stackoverflow.com/questions/799 ... a-property

Вернуться в «C#»