@@ -209,6 +209,17 @@ public double ContentMinWidth
209209 set { SetValue ( ContentMinWidthProperty , value ) ; }
210210 }
211211
212+ public static readonly DependencyProperty RelativeHorizontalOffsetProperty
213+ = DependencyProperty . Register (
214+ nameof ( RelativeHorizontalOffset ) , typeof ( double ) , typeof ( ComboBoxPopup ) ,
215+ new FrameworkPropertyMetadata ( default ( double ) ) ) ;
216+
217+ public double RelativeHorizontalOffset
218+ {
219+ get => ( double ) GetValue ( RelativeHorizontalOffsetProperty ) ;
220+ set => SetValue ( RelativeHorizontalOffsetProperty , value ) ;
221+ }
222+
212223 public ComboBoxPopup ( )
213224 {
214225 CustomPopupPlacementCallback = ComboBoxCustomPopupPlacementCallback ;
@@ -230,7 +241,7 @@ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
230241 private void SetupVisiblePlacementWidth ( IEnumerable < DependencyObject > visualAncestry )
231242 {
232243 var parent = visualAncestry . OfType < Panel > ( ) . ElementAt ( 1 ) ;
233- VisiblePlacementWidth = TreeHelper . GetVisibleWidth ( ( FrameworkElement ) PlacementTarget , parent ) ;
244+ VisiblePlacementWidth = TreeHelper . GetVisibleWidth ( ( FrameworkElement ) PlacementTarget , parent , FlowDirection ) ;
234245 }
235246
236247 private CustomPopupPlacement [ ] ComboBoxCustomPopupPlacementCallback (
@@ -240,13 +251,13 @@ private CustomPopupPlacement[] ComboBoxCustomPopupPlacementCallback(
240251
241252 SetupVisiblePlacementWidth ( visualAncestry ) ;
242253
243- var data = GetPositioningData ( visualAncestry , popupSize , targetSize , offset ) ;
254+ var data = GetPositioningData ( visualAncestry , popupSize , targetSize ) ;
244255 var preferUpIfSafe = data . LocationY + data . PopupSize . Height > data . ScreenHeight ;
245256
246257 if ( ClassicMode
247- || data . LocationX + data . PopupSize . Width - data . RealOffsetX > data . ScreenWidth
248- || data . LocationX - data . RealOffsetX < 0
249- || ! preferUpIfSafe && data . LocationY - Math . Abs ( data . NewDownY ) < 0 )
258+ || data . PopupLocationX + data . PopupSize . Width > data . ScreenWidth
259+ || data . PopupLocationX < 0
260+ || ! preferUpIfSafe && data . LocationY + data . NewDownY < 0 )
250261 {
251262 SetCurrentValue ( PopupPlacementProperty , ComboBoxPopupPlacement . Classic ) ;
252263 return new [ ] { GetClassicPopupPlacement ( this , data ) } ;
@@ -272,7 +283,7 @@ private void SetChildTemplateIfNeed(ControlTemplate template)
272283 }
273284 }
274285
275- private PositioningData GetPositioningData ( IEnumerable < DependencyObject > visualAncestry , Size popupSize , Size targetSize , Point offset )
286+ private PositioningData GetPositioningData ( IEnumerable < DependencyObject > visualAncestry , Size popupSize , Size targetSize )
276287 {
277288 var locationFromScreen = PlacementTarget . PointToScreen ( new Point ( 0 , 0 ) ) ;
278289
@@ -290,15 +301,11 @@ private PositioningData GetPositioningData(IEnumerable<DependencyObject> visualA
290301 var upVerticalOffsetIndependent = DpiHelper . TransformToDeviceY ( mainVisual , UpVerticalOffset ) ;
291302 var newUpY = upVerticalOffsetIndependent - popupSize . Height + targetSize . Height ;
292303 var newDownY = DpiHelper . TransformToDeviceY ( mainVisual , DownVerticalOffset ) ;
293-
294- double offsetX ;
295- const int rtlHorizontalOffset = 20 ;
296-
304+ var offsetX = DpiHelper . TransformToDeviceX ( mainVisual , RelativeHorizontalOffset ) ;
297305 if ( FlowDirection == FlowDirection . LeftToRight )
298- offsetX = DpiHelper . TransformToDeviceX ( mainVisual , offset . X ) ;
306+ offsetX = Round ( offsetX ) ;
299307 else
300- offsetX = DpiHelper . TransformToDeviceX ( mainVisual ,
301- offset . X - targetSize . Width - rtlHorizontalOffset ) ;
308+ offsetX = Math . Truncate ( offsetX - targetSize . Width ) ;
302309
303310 return new PositioningData (
304311 mainVisual , offsetX ,
@@ -308,6 +315,8 @@ private PositioningData GetPositioningData(IEnumerable<DependencyObject> visualA
308315 screenHeight , screenWidth ) ;
309316 }
310317
318+ private static double Round ( double val ) => val < 0 ? ( int ) ( val - 0.5 ) : ( int ) ( val + 0.5 ) ;
319+
311320 private static PropertyChangedCallback CreateTemplatePropertyChangedCallback ( ComboBoxPopupPlacement popupPlacement )
312321 {
313322 return delegate ( DependencyObject d , DependencyPropertyChangedEventArgs e )
@@ -379,7 +388,7 @@ private struct PositioningData
379388 public double OffsetX { get ; }
380389 public double NewUpY { get ; }
381390 public double NewDownY { get ; }
382- public double RealOffsetX => ( PopupSize . Width - TargetSize . Width ) / 2.0 ;
391+ public double PopupLocationX => LocationX + OffsetX ;
383392 public Size PopupSize { get ; }
384393 public Size TargetSize { get ; }
385394 public double LocationX { get ; }
@@ -390,9 +399,9 @@ private struct PositioningData
390399 public PositioningData ( Visual mainVisual , double offsetX , double newUpY , double newDownY , Size popupSize , Size targetSize , double locationX , double locationY , double screenHeight , double screenWidth )
391400 {
392401 MainVisual = mainVisual ;
393- OffsetX = offsetX ;
394- NewUpY = newUpY ;
395- NewDownY = newDownY ;
402+ OffsetX = Round ( offsetX ) ;
403+ NewUpY = Round ( newUpY ) ;
404+ NewDownY = Round ( newDownY ) ;
396405 PopupSize = popupSize ; TargetSize = targetSize ;
397406 LocationX = locationX ; LocationY = locationY ;
398407 ScreenWidth = screenWidth ; ScreenHeight = screenHeight ;
0 commit comments