@@ -593,56 +593,43 @@ protected override void OnOpened(EventArgs e)
593593 }
594594
595595 private void SetupScrollSync ( )
596+ {
597+ // Capture wheel events using Tunnel strategy to intercept before TextEditor handles them
598+ if ( _oursPresenter != null )
599+ _oursPresenter . AddHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged , RoutingStrategies . Tunnel ) ;
600+ if ( _theirsPresenter != null )
601+ _theirsPresenter . AddHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged , RoutingStrategies . Tunnel ) ;
602+ if ( _resultPresenter != null )
603+ _resultPresenter . AddHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged , RoutingStrategies . Tunnel ) ;
604+ }
605+
606+ private void OnPresenterPointerWheelChanged ( object sender , PointerWheelEventArgs e )
596607 {
597608 var oursScroll = _oursPresenter ? . GetScrollViewer ( ) ;
598609 var theirsScroll = _theirsPresenter ? . GetScrollViewer ( ) ;
599610 var resultScroll = _resultPresenter ? . GetScrollViewer ( ) ;
600611
612+ // Calculate scroll delta (negative because wheel up = scroll up = decrease offset)
613+ var delta = e . Delta . Y * 50 ;
614+
615+ // Get current offset
616+ var currentOffset = oursScroll ? . Offset ?? Vector . Zero ;
617+ var newY = Math . Max ( 0 , currentOffset . Y - delta ) ;
618+ var newOffset = new Vector ( currentOffset . X , newY ) ;
619+
620+ // Apply to all scroll viewers
601621 if ( oursScroll != null )
602- oursScroll . ScrollChanged += OnPanelScrollChanged ;
622+ oursScroll . Offset = newOffset ;
603623 if ( theirsScroll != null )
604- theirsScroll . ScrollChanged += OnPanelScrollChanged ;
624+ theirsScroll . Offset = newOffset ;
605625 if ( resultScroll != null )
606- resultScroll . ScrollChanged += OnPanelScrollChanged ;
607- }
608-
609- private void OnPanelScrollChanged ( object sender , ScrollChangedEventArgs e )
610- {
611- if ( _isSyncingScroll || sender is not ScrollViewer source )
612- return ;
613-
614- // Only sync if this panel initiated the scroll (pointer is over it or significant delta)
615- var presenter = source . FindAncestorOfType < MergeDiffPresenter > ( ) ;
616- if ( presenter == null )
617- return ;
618-
619- if ( ! presenter . IsPointerOver && e . OffsetDelta . SquaredLength <= 1.0f )
620- return ;
621-
622- _isSyncingScroll = true ;
623- try
624- {
625- var offset = source . Offset ;
626+ resultScroll . Offset = newOffset ;
626627
627- var oursScroll = _oursPresenter ? . GetScrollViewer ( ) ;
628- var theirsScroll = _theirsPresenter ? . GetScrollViewer ( ) ;
629- var resultScroll = _resultPresenter ? . GetScrollViewer ( ) ;
630-
631- if ( oursScroll != null && oursScroll != source )
632- oursScroll . Offset = offset ;
633- if ( theirsScroll != null && theirsScroll != source )
634- theirsScroll . Offset = offset ;
635- if ( resultScroll != null && resultScroll != source )
636- resultScroll . Offset = offset ;
628+ // Update ViewModel
629+ if ( DataContext is ViewModels . MergeConflictEditor vm )
630+ vm . ScrollOffset = newOffset ;
637631
638- // Update ViewModel
639- if ( DataContext is ViewModels . MergeConflictEditor vm )
640- vm . ScrollOffset = offset ;
641- }
642- finally
643- {
644- _isSyncingScroll = false ;
645- }
632+ e . Handled = true ;
646633 }
647634
648635 private void OnViewModelPropertyChanged ( object sender , System . ComponentModel . PropertyChangedEventArgs e )
@@ -884,50 +871,37 @@ private void ScrollToCurrentConflict()
884871 var targetOffset = new Vector ( 0 , Math . Max ( 0 , vOffset - _oursPresenter . Bounds . Height * 0.3 ) ) ;
885872
886873 // Sync all panels to this offset
887- _isSyncingScroll = true ;
888- try
889- {
890- var oursScroll = _oursPresenter ? . GetScrollViewer ( ) ;
891- var theirsScroll = _theirsPresenter ? . GetScrollViewer ( ) ;
892- var resultScroll = _resultPresenter ? . GetScrollViewer ( ) ;
893-
894- if ( oursScroll != null )
895- oursScroll . Offset = targetOffset ;
896- if ( theirsScroll != null )
897- theirsScroll . Offset = targetOffset ;
898- if ( resultScroll != null )
899- resultScroll . Offset = targetOffset ;
900-
901- vm . ScrollOffset = targetOffset ;
902- }
903- finally
904- {
905- _isSyncingScroll = false ;
906- }
874+ var oursScroll = _oursPresenter ? . GetScrollViewer ( ) ;
875+ var theirsScroll = _theirsPresenter ? . GetScrollViewer ( ) ;
876+ var resultScroll = _resultPresenter ? . GetScrollViewer ( ) ;
877+
878+ if ( oursScroll != null )
879+ oursScroll . Offset = targetOffset ;
880+ if ( theirsScroll != null )
881+ theirsScroll . Offset = targetOffset ;
882+ if ( resultScroll != null )
883+ resultScroll . Offset = targetOffset ;
884+
885+ vm . ScrollOffset = targetOffset ;
907886 }
908887 }
909888 }
910889
911890 protected override void OnClosed ( EventArgs e )
912891 {
913892 // Clean up scroll handlers
914- var oursScroll = _oursPresenter ? . GetScrollViewer ( ) ;
915- var theirsScroll = _theirsPresenter ? . GetScrollViewer ( ) ;
916- var resultScroll = _resultPresenter ? . GetScrollViewer ( ) ;
917-
918- if ( oursScroll != null )
919- oursScroll . ScrollChanged -= OnPanelScrollChanged ;
920- if ( theirsScroll != null )
921- theirsScroll . ScrollChanged -= OnPanelScrollChanged ;
922- if ( resultScroll != null )
923- resultScroll . ScrollChanged -= OnPanelScrollChanged ;
893+ if ( _oursPresenter != null )
894+ _oursPresenter . RemoveHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged ) ;
895+ if ( _theirsPresenter != null )
896+ _theirsPresenter . RemoveHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged ) ;
897+ if ( _resultPresenter != null )
898+ _resultPresenter . RemoveHandler ( PointerWheelChangedEvent , OnPresenterPointerWheelChanged ) ;
924899
925900 base . OnClosed ( e ) ;
926901 GC . Collect ( ) ;
927902 }
928903
929904 private bool _forceClose = false ;
930- private bool _isSyncingScroll = false ;
931905 private MergeDiffPresenter _oursPresenter ;
932906 private MergeDiffPresenter _theirsPresenter ;
933907 private MergeDiffPresenter _resultPresenter ;
0 commit comments