2011-03-24 15 views
11

मध्य माउस बटन (उर्फ: माउस व्हील) पर क्लिक करके और फिर माउस को नीचे ले जाने से उपयोगकर्ताओं को IE में स्क्रॉल करने देता है, और अधिकांश विंडोज ऐप्स। यह व्यवहार डिफ़ॉल्ट रूप से WPF नियंत्रण में अनुपलब्ध प्रतीत होता है? क्या कोई सेटिंग, कामकाज, या कुछ स्पष्ट है कि मुझे याद आ रही है?मैं WPF ScrollViewer मध्य-क्लिक-स्क्रॉल कैसे बना सकता हूं?

+1

माउस मध्य बटन ईवेंट को संभालना संभव है: http://stackoverflow.com/questions/517556/how-to-handle-the-mouse-wheel-click-event-in-wpf। मैं इस घटना को सही तरीके से संभाल और संसाधित करने के लिए टॉमोरो का प्रयास करूंगा। समाधान के लिए – vorrtex

उत्तर

11

मुझे यह पता चला है कि 3 माउस ईवेंट (MouseDown, MouseUp, MouseMove) का उपयोग करके इसे कैसे प्राप्त किया जाए।

<Grid> 
    <ScrollViewer MouseDown="ScrollViewer_MouseDown" MouseUp="ScrollViewer_MouseUp" MouseMove="ScrollViewer_MouseMove"> 
      <StackPanel x:Name="dynamicLongStackPanel"> 

      </StackPanel> 
    </ScrollViewer> 
    <Canvas x:Name="topLayer" IsHitTestVisible="False" /> 
</Grid> 

बेहतर होगा कि बजाय में कोड-पीछे की घटनाओं की एक व्यवहार लिखने के लिए, लेकिन सभी के लिए आवश्यक पुस्तकालय है, और यह भी मैं नहीं: उनके संचालकों नीचे XAML में ScrollViewer तत्व से जुड़े होते हैं Canvas के साथ इसे कैसे कनेक्ट करें, इसे जानें।

ईवेंट हैंडलर्स:

private bool isMoving = false;     //False - ignore mouse movements and don't scroll 
    private bool isDeferredMovingStarted = false; //True - Mouse down -> Mouse up without moving -> Move; False - Mouse down -> Move 
    private Point? startPosition = null; 
    private double slowdown = 200;     //The number 200 is found from experiments, it should be corrected 



    private void ScrollViewer_MouseDown(object sender, MouseButtonEventArgs e) 
    { 
     if (this.isMoving == true) //Moving with a released wheel and pressing a button 
       this.CancelScrolling(); 
     else if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Pressed) 
     { 
      if (this.isMoving == false) //Pressing a wheel the first time 
      { 
       this.isMoving = true; 
       this.startPosition = e.GetPosition(sender as IInputElement); 
       this.isDeferredMovingStarted = true; //the default value is true until the opposite value is set 

       this.AddScrollSign(e.GetPosition(this.topLayer).X, e.GetPosition(this.topLayer).Y); 
      } 
     } 
    } 

    private void ScrollViewer_MouseUp(object sender, MouseButtonEventArgs e) 
    { 
     if (e.ChangedButton == MouseButton.Middle && e.ButtonState == MouseButtonState.Released && this.isDeferredMovingStarted != true) 
      this.CancelScrolling(); 
    } 

    private void CancelScrolling() 
    { 
     this.isMoving = false; 
     this.startPosition = null; 
     this.isDeferredMovingStarted = false; 
     this.RemoveScrollSign(); 
    } 

    private void ScrollViewer_MouseMove(object sender, MouseEventArgs e) 
    { 
     var sv = sender as ScrollViewer; 

     if (this.isMoving && sv != null) 
     { 
      this.isDeferredMovingStarted = false; //standard scrolling (Mouse down -> Move) 

      var currentPosition = e.GetPosition(sv); 
      var offset = currentPosition - startPosition.Value; 
      offset.Y /= slowdown; 
      offset.X /= slowdown; 

      //if(Math.Abs(offset.Y) > 25.0/slowdown) //Some kind of a dead space, uncomment if it is neccessary 
      sv.ScrollToVerticalOffset(sv.VerticalOffset + offset.Y); 
      sv.ScrollToHorizontalOffset(sv.HorizontalOffset + offset.X); 
     } 
    } 

तो प्रणाली को बुलाती है AddScrollSign और RemoveScrollSign इस उदाहरण काम करेंगे दूर करने के लिए।

private void AddScrollSign(double x, double y) 
    { 
     int size = 50; 
     var img = new BitmapImage(new Uri(@"d:\middle_button_scroll.png")); 
     var adorner = new Image() { Source = img, Width = size, Height = size }; 
     //var adorner = new Ellipse { Stroke = Brushes.Red, StrokeThickness = 2.0, Width = 20, Height = 20 }; 

     this.topLayer.Children.Add(adorner); 
     Canvas.SetLeft(adorner, x - size/2); 
     Canvas.SetTop(adorner, y - size/2); 
    } 

    private void RemoveScrollSign() 
    { 
     this.topLayer.Children.Clear(); 
    } 

माउस का उदाहरण:: enter image description hereenter image description here

और एक आखिरी टिप्पणी: लेकिन मैं 2 तरीकों जो स्क्रॉल आइकन निर्धारित के साथ विस्तार किया है वहाँ रास्ता Press -> Immediately Release -> Move के साथ कुछ समस्याएं हैं। यदि उपयोगकर्ता माउस बाएं बटन, या कीबोर्ड की किसी भी कुंजी पर क्लिक करता है, या एप्लिकेशन फोकस खो देता है तो स्क्रॉलिंग रद्द करना माना जाता है। कई घटनाएं हैं और मेरे पास उन सभी को संभालने का समय नहीं है।

लेकिन मानक तरीका Press -> Move -> Release समस्याओं के बिना काम करता है।

+0

+1, मेरे पास कुछ सुझाव हैं, कृपया मेरा अलग उत्तर देखें –

2

vorrtex एक अच्छा समाधान तैनात, कृपया उसे वोट दें!

मेरे पास उनके समाधान के लिए कुछ सुझाव हैं, हालांकि, टिप्पणियों में उन सभी को फिट करने के लिए बहुत लंबा है, इसलिए मैं एक अलग उत्तर पोस्ट करता हूं और उसे निर्देशित करता हूं!

आप प्रेस-> रिलीज-> मूव के साथ समस्याओं का उल्लेख करते हैं। जब माउस स्क्रॉल व्यूअर पर नहीं है तब भी आपको MouseEvents प्राप्त करने के लिए MouseCapturing का उपयोग करना चाहिए। मैंने इसका परीक्षण नहीं किया है, लेकिन मुझे लगता है कि आपका समाधान भी Press->Move->Move outside of ScrollViewer->Release में विफल रहता है, माउसकैप्चरिंग भी इसका ख्याल रखेगी।

इसके अलावा आप एक व्यवहार का उपयोग करने का उल्लेख करते हैं। मैं एक attached behavior का सुझाव देना चाहूंगा जिसके लिए अतिरिक्त निर्भरताओं की आवश्यकता नहीं है।

आपको निश्चित रूप से अतिरिक्त कैनवास का उपयोग नहीं करना चाहिए बल्कि इसे एडॉर्नर में करना चाहिए।

स्क्रॉलव्यूयर स्वयं स्क्रॉलकंटेंट प्रस्तुतकर्ता होस्ट करता है जो एक एडॉर्नरलेयर को परिभाषित करता है। आपको वहां एडॉर्नर डालना चाहिए। यह किसी और निर्भरता की आवश्यकता को हटा देता है और संलग्न व्यवहार को IsMiddleScrollable="true" के रूप में सरल रखता है।

+0

माउस कैप्चर को कार्यान्वित करना मुश्किल नहीं है, मैं कुछ घंटों के बाद ऐसा करूँगा।लेकिन अन्य टिप्पणियां इतनी सादा नहीं हैं। अगर मैं संलग्न संपत्ति या व्यवहार का उपयोग करता हूं - मैं स्क्रॉल छवि को 'कैनवास' में नहीं जोड़ पाऊंगा। दूसरी तरफ 'स्क्रॉलकंटेंट प्रिंटर' नियंत्रण 'स्क्रॉलव्यूअर' के टेम्पलेट के अंदर स्थित है और मुझे लगता है कि मुझे आंतरिक भागों तक पहुंचने के लिए विरासत नियंत्रण बनाना होगा। मैं इसके साथ कुछ करने की कोशिश करूंगा, लेकिन मुझे यकीन नहीं है कि नया नियंत्रण ईवेंट हैंडलर के सेट से बेहतर है या नहीं। – vorrtex

+0

माउसमोव ईवेंट को कैप्चर करने के बाद माउस को केवल एक बार कहा जाता है। मुझे एक टाइमर बनाना होगा जो चलती कार्यक्षमता के साथ विधि को ट्रिगर करेगा। सबकुछ अधिक जटिल हो जाता है। – vorrtex

+0

@ vorrtex मेरे पास कल शाम होगा। जैसा कि मुझे एक अच्छा कॉम्पैक्ट समाधान में भी रूचि है, मैं इसमें एक गोताखोरी ले जाऊंगा! –