2012-04-11 4 views
12

के साथ स्क्रॉलव्यूयर क्षैतिज स्नैपपॉइंट्स को सक्षम करना मैं विंडोज 8 एसडीके नमूने से स्क्रॉलव्यूयर नमूने में समान अनुभव बनाने की कोशिश कर रहा हूं ताकि बाएं और दाएं स्क्रॉल करते समय स्क्रॉलव्यूयर के अंदर आइटमों को स्नैप करने में सक्षम हो सकें। नमूना (जो काम करता है) से कार्यान्वयन इस तरह है:बाइंडेबल संग्रह

<ScrollViewer x:Name="scrollViewer" Width="480" Height="270" 
       HorizontalAlignment="Left" VerticalAlignment="Top" 
       VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" 
       ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory"> 
    <StackPanel Orientation="Horizontal"> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
    </StackPanel> 
</ScrollViewer> 

मेरी वांछित कार्यान्वयन के साथ फर्क सिर्फ इतना है कि मैं नहीं चाहता कि एक StackPanel आइटम के साथ अंदर चाहते हैं, लेकिन कुछ मैं करने के लिए बाध्य कर सकते हैं। मैं एक ItemsControl साथ यह पूरा करने की कोशिश कर रहा हूँ, लेकिन किसी कारण से स्नैप व्यवहार लात नहीं करता:

<ScrollViewer x:Name="scrollViewer" Width="480" Height="270" 
       HorizontalAlignment="Left" VerticalAlignment="Top" 
       VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" 
       ZoomMode="Disabled" HorizontalSnapPointsType="Mandatory"> 
    <ItemsControl> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Orientation="Horizontal" /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a cliff" Source="images/cliff.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of Grapes" Source="images/grapes.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of Mount Rainier" Source="images/Rainier.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a sunset" Source="images/sunset.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
     <Image Width="480" Height="270" AutomationProperties.Name="Image of a valley" Source="images/valley.jpg" Stretch="None" HorizontalAlignment="Left" VerticalAlignment="Top"/> 
    </ItemsControl> 
</ScrollViewer> 

सुझाव बहुत सराहना की जाएगी!


डेनिस के लिए धन्यवाद, मैं ItemsControl पर निम्नलिखित शैली का उपयोग कर समाप्त हो गया और ScrollViewer हटा दिया और पूरी तरह ItemsPanelTemplate इनलाइन: बाध्य संग्रह मुश्किल हो सकता है के लिए काम करने के लिए

<Style x:Key="ItemsControlStyle" TargetType="ItemsControl"> 
    <Setter Property="ItemsPanel"> 
     <Setter.Value> 
      <ItemsPanelTemplate> 
       <VirtualizingStackPanel Orientation="Horizontal"/> 
      </ItemsPanelTemplate> 
     </Setter.Value> 
    </Setter> 
    <Setter Property="Template"> 
     <Setter.Value> 
      <ControlTemplate TargetType="ItemsControl"> 
       <ScrollViewer Style="{StaticResource HorizontalScrollViewerStyle}" HorizontalSnapPointsType="Mandatory"> 
        <ItemsPresenter /> 
       </ScrollViewer> 
      </ControlTemplate> 
     </Setter.Value> 
    </Setter> 
</Style> 

उत्तर

11

स्नैप अंक हो रही है। ScrollViewer के तत्काल बच्चे को काम करने के लिए स्नैप पॉइंट्स के लिए IScrollSnapPointsInfo इंटरफ़ेस को कार्यान्वित करना चाहिए। ItemControl IScrollSnapPointsInfo को लागू नहीं करता है और इसके परिणामस्वरूप आप स्नैपिंग व्यवहार नहीं देख पाएंगे।

इस मुद्दे आप कुछ विकल्प मिल गया हल करने के लिए:

  • ItemsControl से ली गई कस्टम वर्ग बनाएँ और IScrollSnapPointsInfo इंटरफ़ेस को लागू।
  • आइटम नियंत्रण के लिए कस्टम शैली बनाएं और स्टाइल के अंदर स्क्रॉलव्यूयर पर क्षैतिज स्नैपपॉइंट टाइप करें।

मैंने पूर्व दृष्टिकोण लागू किया है और यह पुष्टि कर सकता है कि यह काम करता है, लेकिन आपके मामले में कस्टम शैली बेहतर विकल्प हो सकती है।

+4

क्या हमें एक उदाहरण प्रदान करना संभव है? – yalematta

1

ठीक है, यहां बाइंड किए गए आइटम और सही ढंग से काम करने वाले स्नैपिंग के साथ क्षैतिज सूची दृश्य के लिए सबसे सरल (और स्टैंडअलोन) उदाहरण है (निम्नलिखित कोड में टिप्पणियां देखें)।

XAML:

<ListView x:Name="YourListView" 
       ItemsSource="{x:Bind Path=Items}" 
       Loaded="YourListView_OnLoaded"> 
     <!--Set items panel to horizontal--> 
     <ListView.ItemsPanel> 
      <ItemsPanelTemplate> 
       <ItemsStackPanel Orientation="Horizontal" /> 
      </ItemsPanelTemplate> 
     </ListView.ItemsPanel> 
     <!--Some item template--> 
     <ListView.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding}"/> 
      </DataTemplate> 
     </ListView.ItemTemplate> 
    </ListView> 

पृष्ठभूमि कोड:

private void YourListView_OnLoaded(object sender, RoutedEventArgs e) 
    { 
     //get ListView 
     var yourList = sender as ListView; 

     //*** yourList style-based changes *** 
     //see Style here https://msdn.microsoft.com/en-us/library/windows/apps/mt299137.aspx 

     //** Change orientation of scrollviewer (name in the Style "ScrollViewer") ** 
     //1. get scrollviewer (child element of yourList) 
     var sv = GetFirstChildDependencyObjectOfType<ScrollViewer>(yourList); 

     //2. enable ScrollViewer horizontal scrolling 
     sv.HorizontalScrollMode =ScrollMode.Auto; 
     sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; 
     sv.IsHorizontalRailEnabled = true; 

     //3. disable ScrollViewer vertical scrolling 
     sv.VerticalScrollMode = ScrollMode.Disabled; 
     sv.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled; 
     sv.IsVerticalRailEnabled = false; 
     // //no we have horizontally scrolling ListView 


     //** Enable snapping ** 
     sv.HorizontalSnapPointsType = SnapPointsType.MandatorySingle; //or you can use SnapPointsType.Mandatory 
     sv.HorizontalSnapPointsAlignment = SnapPointsAlignment.Near; //example works only for Near case, for other there should be some changes 
     // //no we have horizontally scrolling ListView with snapping and "scroll last item into view" bug (about bug see here http://stackoverflow.com/questions/11084493/snapping-scrollviewer-in-windows-8-metro-in-wide-screens-not-snapping-to-the-las) 

     //** fix "scroll last item into view" bug ** 
     //1. Get items presenter (child element of yourList) 
     var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(yourList); 
     // or var ip = GetFirstChildDependencyObjectOfType<ItemsPresenter>(sv); //also will work here 

     //2. Subscribe to its SizeChanged event 
     ip.SizeChanged += ip_SizeChanged; 

     //3. see the continuation in: private void ip_SizeChanged(object sender, SizeChangedEventArgs e) 
    } 


    public static T GetFirstChildDependencyObjectOfType<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj is T) return depObj as T; 

     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      var child = VisualTreeHelper.GetChild(depObj, i); 

      var result = GetFirstChildDependencyObjectOfType<T>(child); 
      if (result != null) return result; 
     } 
     return null; 
    } 

    private void ip_SizeChanged(object sender, SizeChangedEventArgs e) 
    { 
     //3.0 if rev size is same as new - do nothing 
     //here should be one more condition added by && but it is a little bit complicated and rare, so it is omitted. 
     //The condition is: yourList.Items.Last() must be equal to (yourList.Items.Last() used on previous call of ip_SizeChanged) 
     if (e.PreviousSize.Equals(e.NewSize)) return; 

     //3.1 get sender as our ItemsPresenter 
     var ip = sender as ItemsPresenter; 

     //3.2 get the ItemsPresenter parent to get "viewable" width of ItemsPresenter that is ActualWidth of the Scrollviewer (it is scrollviewer actually, but we need just its ActualWidth so - as FrameworkElement is used) 
     var sv = ip.Parent as FrameworkElement; 

     //3.3 get parent ListView to be able to get elements Containers 
     var yourList = GetParent<ListView>(ip); 

     //3.4 get last item ActualWidth 
     var lastItem = yourList.Items.Last(); 
     var lastItemContainerObject = yourList.ContainerFromItem(lastItem); 
     var lastItemContainer = lastItemContainerObject as FrameworkElement; 
     if (lastItemContainer == null) 
     { 
      //NO lastItemContainer YET, wait for next call 
      return; 
     } 
     var lastItemWidth = lastItemContainer.ActualWidth; 

     //3.5 get margin fix value 
     var rightMarginFixValue = sv.ActualWidth - lastItemWidth; 

     //3.6. fix "scroll last item into view" bug 
     ip.Margin = new Thickness(ip.Margin.Left, 
      ip.Margin.Top, 
      ip.Margin.Right + rightMarginFixValue, //APPLY FIX 
      ip.Margin.Bottom); 
    } 

    public static T GetParent<T>(DependencyObject reference) where T : class 
    { 
     var depObj = VisualTreeHelper.GetParent(reference); 
     if (depObj == null) return (T)null; 
     while (true) 
     { 
      var depClass = depObj as T; 
      if (depClass != null) return depClass; 
      depObj = VisualTreeHelper.GetParent(depObj); 
      if (depObj == null) return (T)null; 
     } 
    } 

इस उदाहरण के बारे में।

  1. अधिकांश चेक और त्रुटियों का संचालन छोड़ दिया जाता है।

  2. आप ListView शैली/खाका ओवरराइड करते हैं, तो VisualTree खोज भागों, उसके अनुसार परिवर्तित किया जाना चाहिए

  3. मैं नहीं बल्कि इस तर्क के साथ ListView नियंत्रण से विरासत में मिली बनाएंगे उपयोग की तुलना में उदाहरण प्रदान की वास्तविक कोड में के रूप में है।
  4. समान कोड वर्टिकल केस (या दोनों) के लिए छोटे बदलावों के साथ काम करता है।
  5. उल्लेख किया गया स्नैपिंग बग - स्नैपपॉइंट्स टाइप करने के स्क्रॉलव्यूयर बग। मैंडेटरी सिंगल और स्नैपपॉइंट्स टाइप। मैंडरी केस।यह आइटमों के लिए प्रदर्शित नहीं है

+0

इस नमूने के लिए धन्यवाद, यह इस महत्वपूर्ण प्रश्न पर होना अच्छा है। Fyi, हालांकि, पीछे कोड आवश्यक नहीं है। आप कोड-बैक में सेट की गई सभी गुणों को सेट करने के लिए शैली का उपयोग कर सकते हैं। (मुझे उन बगों के बारे में पता नहीं है जिन्हें आप उल्लेख कर रहे हैं) –

संबंधित मुद्दे