2015-10-16 93 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條記錄以及自定義模板,對嗎? –

相關問題