2012-07-24 81 views
3

我正在創建一個滾動的surfacelistbox,它在拖動完成後自動捕捉到一個位置,以便屏幕上的中心項目自己居中在視口中。捕捉SurfaceListBox

我已經得到了中心項目,但像往常一樣,WPF處理大小,屏幕位置和偏移量的方式讓我感到困惑。

目前我已經選擇訂閱SurfaceScrollViewer的ManipulationCompleted事件,因爲在完成滾動手勢(而ScrollChanged事件趨於提前觸發)後,這似乎始終如此。

void ManipCompleted(object sender, ManipulationCompletedEventArgs e) 
{ 
    FocusTaker.Focus(); //reset focus to a dummy element 
    List<FrameworkElement> visibleElements = new List<FrameworkElement>(); 
    for (int i = 0; i < List.Items.Count; i++) 
    { 
     SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem; 
     if (ViewportHelper.IsInViewport(item) && (List.Items[i] as string != "Dummy")) 
     { 
      FrameworkElement el = item as FrameworkElement; 
      visibleElements.Add(el); 
     } 
    } 

    int centerItemIdx = visibleElements.Count/2; 
    FrameworkElement centerItem = visibleElements[centerItemIdx]; 

    double center = ss.ViewportWidth/2; 

    //ss is the SurfaceScrollViewer 
    Point itemPosition = centerItem.TransformToAncestor(ss).Transform(new Point(0, 0)); 

    double desiredOffset = ss.HorizontalOffset + (center - itemPosition.X); 

    ss.ScrollToHorizontalOffset(desiredOffset); 

    centerItem.Focus(); //this also doesn't seem to work, but whatever. 
} 

該列表捕捉,但它捕捉的地方似乎有點混亂。我沿着屏幕的中心有一條線,有時它看起來正好在項目的中間,但有時候它偏離了一邊,甚至在項目之間。不能完全明白,但似乎列表的第一和第四四分位工作得很好,但第二和第三位逐漸向中心偏離。

只是尋找一些關於如何在WPF中使用定位的幫助。所有的相對性以及基於百分比的座標和「屏幕單位」座標之間的差異在這一點上讓我有些困惑。

回答

2

大量的試驗和錯誤的之後,我結束了與此:

void ManipCompleted(object sender, ManipulationCompletedEventArgs e) 
{ 
    FocusTaker.Focus(); //reset focus 
    List<FrameworkElement> visibleElements = new List<FrameworkElement>(); 
    for (int i = 0; i < List.Items.Count; i++) 
    { 
     SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem; 
     if (ViewportHelper.IsInViewport(item)) 
     { 
      FrameworkElement el = item as FrameworkElement; 
      visibleElements.Add(el); 
     } 
    } 

    Window window = Window.GetWindow(this); 

    double center = ss.ViewportWidth/2; 

    double closestCenterOffset = double.MaxValue; 
    FrameworkElement centerItem = visibleElements[0]; 
    foreach (FrameworkElement el in visibleElements) 
    { 
     double centerOffset = Math.Abs(el.TransformToAncestor(window).Transform(new Point(0, 0)).X + (el.ActualWidth/2) - center); 
     if (centerOffset < closestCenterOffset) 
     { 
      closestCenterOffset = centerOffset; 
      centerItem = el; 
     } 
    }       

    Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0)); 

    double desiredOffset = ss.HorizontalOffset - (center - itemPosition.X) + (centerItem.ActualWidth/2); 

    ss.ScrollToHorizontalOffset(desiredOffset); 

    centerItem.Focus(); 
} 

這個代碼塊有效地確定哪一個可見列表元素重疊列表的中心線和卡那元件的確切中心位置。捕捉有點突然,所以我不得不看看某種動畫,但除此之外我相當滿意!我可能會從這裏使用動畫的東西:http://blogs.msdn.com/b/delay/archive/2009/08/04/scrolling-so-smooth-like-the-butter-on-a-muffin-how-to-animate-the-horizontal-verticaloffset-properties-of-a-scrollviewer.aspx

編輯:好吧,沒多久。我擴展了ScrollViewerOffsetMediator以包含Horizo​​ntalOffset,然後簡單地創建了上述文章中建議的動畫。奇蹟般有效。希望這能最終幫助別人。

EDIT2:下面是果snaplist的全碼:

SnapList.xaml

SnapList.xaml.cs

注意,我很懶惰,因爲這項目上的去硬編碼了一些。需要一些自由裁量權來確定你做什麼和不想從這段代碼中得到什麼。不過,我認爲這應該很適合任何想要這個功能的人。

該代碼也改變了我上面粘貼的內容;我發現使用Windows.GetWindow時,列表被放在一個可以移動的控件中,結果不好。我做到了,所以你可以爲你的運動分配一個控制權(相對於層次結構中的推薦控制器)。我認爲其他一些事情也發生了變化;我添加了很多自定義選項,包括能夠爲列表定義自定義焦點。

+0

你可以通過任何機會發布包含動畫的代碼嗎?謝謝。也感謝您爲您的問題提供答案。 – Sabuncu 2013-04-10 10:33:10

+1

嗨Sabuncu,我剛剛添加了控件的完整代碼的pastebins。希望你會在那裏找到你需要的。請注意,它非常粗糙,其中一些特定於我的應用程序的目的,但我希望你能得到你所需要的。 – 2013-04-24 14:28:47

+0

+2謝謝!將嘗試並報告。 – Sabuncu 2013-04-24 19:30:47