2015-10-16 64 views
1

这里有要求。插入一个项目在一个ItemsControl

在我的ItemsControl(如果可以帮助您考虑场景,可以使用ListView)。我想注入,而不是一个记录,但一个独特的DataTemplate到我的列表中的任意索引位置。

例如,我可能希望将其插入到第一位置时,索引0,或第三位置时,索引2,或者甚至有将其插入到最后的位置的逻辑,索引计数1。

我需要子类的ListView做到这一点,我才明白。这就是说,我可以轻松创建SpecialItemTemplate,SpecialItemIndex DP属性来获取值。

补充要求:

  1. 不要求特殊类型的集合
  2. 不要求操作现有的数据
  3. 允许IsHitTestVisible是可变的,太

任何想法如何完成这一壮举(在WinRT中)?

+0

你在这种情况下杰里在做虚拟化? ....你只需要选择一个星期五问。 :P –

+0

我认为这与虚拟化不太相称。所以,要保持简单,让我们说不。有办法做到这一点,对吧?我只知道有。 –

+0

克里斯你真正的解决这个问题,而不是一种破解方式,我会送你一个Lumia 820和一件微软衬衫作为谢谢。没有开玩笑。那如何毁了你的周末? –

回答

1

这是一个解决方案,基本上是一个BehaviorTemplate属性,它可以连接到任何ItemsControl。我使用虚拟化和非虚拟化面板对其进行了测试,适用于这两种情况。如果你认为代码是错综复杂的......好吧,我不能不同意,写了一段时间,我不记得我有什么理由按它的方式写它。

用法:

<ListBox ItemsSource="{Binding Persons}"> 

    <Interactivity:Interaction.Behaviors> 
     <AlternativeItemTemplate Index="42"> 
      <DataTemplate> 
       ...foo... 
      </DataTemplate> 
     </AlternativeItemTemplate> 
    </Interactivity:Interaction.Behaviors> 

    <ListBox.ItemTemplate> 
     <DataTemplate> 
      ...bar... 
     </DataTemplate> 
    </ListBox.ItemTemplate> 

</ListBox> 

和类:

[ContentProperty("ItemTemplate")] 
public class AlternativeItemTemplate : ItemContainerDecorator 
{ 
    public DataTemplate ItemTemplate 
    { 
     get { return (DataTemplate) GetValue(ItemTemplateProperty); } 
     set { SetValue(ItemTemplateProperty, value); } 
    } 

    public static readonly DependencyProperty ItemTemplateProperty = 
     DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(AlternativeItemTemplate), new PropertyMetadata(null)); 

    public int Index 
    { 
     get { return (int) GetValue(IndexProperty); } 
     set { SetValue(IndexProperty, value); } 
    } 

    public static readonly DependencyProperty IndexProperty = 
     DependencyProperty.Register("Index", typeof(int), typeof(AlternativeItemTemplate), new PropertyMetadata(-1)); 

    protected override void OnContainersChanged() 
    { 
     if (!AssociatedObject.Items.Any() || Index < 0 || Index >= AssociatedObject.Items.Count) 
     { 
      ItemContentPresenter = null; 
      ItemContentControl = null; 
      m_overwrittenTemplate = null; 
      return; 
     } 

     TryUpdateItem(ItemContainerGenerator.ContainerFromItem(AssociatedObject.Items[Index])); 
    } 

    private ContentPresenter ItemContentPresenter { get; set; } 
    private ContentControl ItemContentControl { get; set; } 
    private DataTemplate m_overwrittenTemplate; 

    private void TryUpdateItem(DependencyObject itemContainer) 
    { 
     if (itemContainer == null) 
     { 
      ResetOverwrittenTemplate(); 
     } 

     var containerAsPresenter = itemContainer as ContentPresenter; 
     if (containerAsPresenter != null) UpdateItemContentPresenter(containerAsPresenter); 
     else 
     { 
      var containerAsControl = itemContainer as ContentControl; 
      if (containerAsControl != null) UpdateItemContentControl(containerAsControl); 
     } 
    } 

    private void ResetOverwrittenTemplate() 
    { 
     if (ItemContentPresenter != null) 
      ItemContentPresenter.ContentTemplate = m_overwrittenTemplate; 

     if (ItemContentControl != null) 
      ItemContentControl.ContentTemplate = m_overwrittenTemplate; 

     ItemContentPresenter = null; 
     ItemContentControl = null; 

     m_overwrittenTemplate = null; 
    } 

    private void UpdateItemContentPresenter(ContentPresenter container) 
    { 
     if (ItemContentPresenter != null) 
      ItemContentPresenter.ContentTemplate = m_overwrittenTemplate; 

     ItemContentPresenter = container; 
     m_overwrittenTemplate = ItemContentPresenter.ContentTemplate; 
     ItemContentPresenter.ContentTemplate = ItemTemplate; 
    } 

    private void UpdateItemContentControl(ContentControl container) 
    { 
     if (ItemContentControl != null) 
      ItemContentControl.ContentTemplate = m_overwrittenTemplate; 

     ItemContentControl = container; 
     m_overwrittenTemplate = ItemContentControl.ContentTemplate; 
     ItemContentControl.ContentTemplate = ItemTemplate; 
    } 
} 

public abstract class ItemContainerDecorator : Behavior<ItemsControl> 
{ 
    private Dictionary<object, DependencyObject> LastKnownContainers = new Dictionary<object, DependencyObject>(); 

    protected ItemContainerGenerator ItemContainerGenerator { get { return (AssociatedObject != null) ? AssociatedObject.ItemContainerGenerator : null; } } 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     ItemContainerGenerator.ItemsChanged += HandleItemsChangedInitially; 

     if (!TryAddObservers()) 
     { 
      AssociatedObject.Loaded += AddObserversOnLoaded; 
     } 

     AssociatedObject.Loaded += OnItemsControlLoaded; 
     AssociatedObject.LayoutUpdated += OnItemsControlLayoutUpdated; 

     CheckContainersChanged(); 
    } 

    private void OnItemsControlLayoutUpdated(object sender, EventArgs eventArgs) 
    { 
     CheckContainersChanged(); 
    } 

    private void OnItemsControlLoaded(object sender, RoutedEventArgs e) 
    { 
     CheckContainersChanged(); 
    } 

    private void AddObserversOnLoaded(object sender, RoutedEventArgs e) 
    { 
     AssociatedObject.Loaded -= AddObserversOnLoaded; 
     TryAddObservers(); 
    } 

    private bool TryAddObservers() 
    { 
     const bool success = true; 
     Panel itemsHost = 
      AssociatedObject.GetVisualDescendants().OfType<Panel>().FirstOrDefault(panel => panel.IsItemsHost); 

     if (itemsHost != null) 
     { 
      var virtualizingItemsHost = itemsHost as VirtualizingPanel; 
      if (virtualizingItemsHost != null) 
      { 
       virtualizingItemsHost.LayoutUpdated += OnVirtualizingItemsHostLayoutUpdated; 
       m_virtualizingItemsHost = virtualizingItemsHost; 
      } 
      return success; 
     } 
     return !success; 
    } 

    private VirtualizingPanel m_virtualizingItemsHost; 
    private bool LayoutUpdatedOccurredFirst; 

    private void OnVirtualizingItemsHostLayoutUpdated(object sender, EventArgs eventArgs) 
    { 
     LayoutUpdatedOccurredFirst = true; 
     CheckContainersChanged(); 
    } 

    protected override void OnDetaching() 
    { 
     ItemContainerGenerator.ItemsChanged -= HandleItemsChangedInitially; 
     ItemContainerGenerator.ItemsChanged -= HandleItemsChanged; 

     AssociatedObject.Loaded -= OnItemsControlLoaded; 
     AssociatedObject.LayoutUpdated -= OnItemsControlLayoutUpdated; 

     AssociatedObject.Loaded -= AddObserversOnLoaded; 
     if (m_virtualizingItemsHost != null) m_virtualizingItemsHost.LayoutUpdated -= OnVirtualizingItemsHostLayoutUpdated; 
     m_virtualizingItemsHost = null; 

     base.OnDetaching(); 
    } 

    private void HandleItemsChangedInitially(object sender, ItemsChangedEventArgs e) 
    { 
     ItemContainerGenerator.ItemsChanged -= HandleItemsChangedInitially; 

     if (!LayoutUpdatedOccurredFirst) 
     { 

      //sometimes calling UpdateLayout throws an ArgumentException 
      //don't know why so we just swallow it 
      //it's not particularly important 
      try 
      { 
       AssociatedObject.UpdateLayout(); 
      } 
      catch (ArgumentException) { } 
     } 

     ItemContainerGenerator.ItemsChanged += HandleItemsChanged; 
     CheckContainersChanged(); 
    } 

    private void HandleItemsChanged(object sender, ItemsChangedEventArgs e) 
    { 
     CheckContainersChanged(); 
    } 

    private void CheckContainersChanged() 
    { 
     var newestContainers = new Dictionary<object, DependencyObject>(); 
     foreach (var item in AssociatedObject.Items) 
     { 
      newestContainers[item] = ItemContainerGenerator.ContainerFromItem(item); 
     } 

     if (!LastKnownContainers.SequenceEqual(newestContainers)) 
     { 
      LastKnownContainers = newestContainers; 
      OnContainersChanged(); 
     } 
    } 

    protected abstract void OnContainersChanged(); 
} 
+0

这需要一些时间来解析。如果数据源不可观察,它会工作吗?它会覆盖一条记录还是将它推出? –

+0

@ JerryNixon-MSFT:它可以处理任何数据源,除了关联的对象必须是ItemsControl以外,没有关于环境的假设。不,它不覆盖/推出任何记录,实际上所有记录都没有改变。它搜索项目的可视化表示(被称为'itemcontainer'),并改变其'Template',这是所有(甚至恢复旧模板后) – Martin

+0

啊,是啊。老实说,我认为这可能是唯一可行的方法。因此,如果我有5条记录显示,并且我以这种方式注入了您的行为,那么我只会显示4条记录以及自定义模板,对吗? –

相关问题