using System.Collections; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Markup; namespace HandyControl.Controls { /// /// ItemsControl的轻量级版本 /// [DefaultProperty("Items")] [ContentProperty("Items")] [TemplatePart(Name = ElementPanel, Type = typeof(Panel))] public class SimpleItemsControl : Control { private const string ElementPanel = "PART_Panel"; public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register( "ItemTemplate", typeof(DataTemplate), typeof(SimpleItemsControl), new FrameworkPropertyMetadata(default(DataTemplate), OnItemTemplateChanged)); public static readonly DependencyProperty ItemContainerStyleProperty = DependencyProperty.Register( "ItemContainerStyle", typeof(Style), typeof(SimpleItemsControl), new PropertyMetadata(default(Style), OnItemContainerStyleChanged)); public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( "ItemsSource", typeof(IEnumerable), typeof(SimpleItemsControl), new PropertyMetadata(default(IEnumerable), OnItemsSourceChanged)); public SimpleItemsControl() { var items = new ObservableCollection(); items.CollectionChanged += OnItemsChanged; Items = items; } public IEnumerable ItemsSource { get => (IEnumerable)GetValue(ItemsSourceProperty); set => SetValue(ItemsSourceProperty, value); } [Bindable(true)] [Category("Content")] public Style ItemContainerStyle { get => (Style)GetValue(ItemContainerStyleProperty); set => SetValue(ItemContainerStyleProperty, value); } [Bindable(true)] public DataTemplate ItemTemplate { get => (DataTemplate)GetValue(ItemTemplateProperty); set => SetValue(ItemTemplateProperty, value); } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] [Bindable(true)] public Collection Items { get; } internal Panel ItemsHost { get; set; } private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((SimpleItemsControl)d).OnItemsSourceChanged((IEnumerable)e.OldValue, (IEnumerable)e.NewValue); } protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) { } public override void OnApplyTemplate() { ItemsHost?.Children.Clear(); base.OnApplyTemplate(); ItemsHost = GetTemplateChild(ElementPanel) as Panel; Refresh(); } protected virtual void OnItemsChanged(object sender, NotifyCollectionChangedEventArgs e) { Refresh(); UpdateItems(); } protected virtual DependencyObject GetContainerForItemOverride() => new ContentPresenter(); protected virtual bool IsItemItsOwnContainerOverride(object item) => item is ContentPresenter; protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item) { switch (element) { case ContentControl contentControl: contentControl.Content = item; contentControl.ContentTemplate = ItemTemplate; break; case ContentPresenter contentPresenter: contentPresenter.Content = item; contentPresenter.ContentTemplate = ItemTemplate; break; } } private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as SimpleItemsControl)?.OnItemTemplateChanged(e); protected virtual void OnItemTemplateChanged(DependencyPropertyChangedEventArgs e) => Refresh(); private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) => (d as SimpleItemsControl)?.OnItemContainerStyleChanged(e); protected virtual void OnItemContainerStyleChanged(DependencyPropertyChangedEventArgs e) => Refresh(); protected virtual void Refresh() { if (ItemsHost == null) return; ItemsHost.Children.Clear(); foreach (var item in Items) { DependencyObject container; if (IsItemItsOwnContainerOverride(item)) { container = item as DependencyObject; } else { container = GetContainerForItemOverride(); PrepareContainerForItemOverride(container, item); } if (container is FrameworkElement element) { element.Style = ItemContainerStyle; ItemsHost.Children.Add(element); } } } protected virtual void UpdateItems() { } } }