c# – 在调整子级大小时保持scrollviewer的相对滚动条偏移量
我有一个带有网格的滚动查看器作为孩子.我正在更改网格的宽度和高度属性以显示不同的“缩放”级别.网格包含2行,其中包含许多图像列,大小相同.
但是,我希望滚动条的相对位置保持不变.在更改网格大小后,屏幕中心的任何内容仍应位于屏幕中央. 默认“放大”视图: private void SizeGrid() { grid1.Width = (scrollViewer1.ViewportWidth / 2) * grid1.ColumnDefinitions.Count; grid1.Height = (scrollViewer1.ViewportHeight / 2) * grid1.RowDefinitions.Count; } “缩小”观点: private void scrollViewer1_KeyDown(object sender,KeyEventArgs e) { if (e.KeyboardDevice.IsKeyDown(Key.Insert)) { grid1.Width = (scrollViewer1.ViewportWidth / 2) * grid1.ColumnDefinitions.Count / 5; grid1.Height = (scrollViewer1.ViewportHeight / 2) * grid1.RowDefinitions.Count / 3; } } 我做了什么…… 如果我知道哪个列是关注的(我不想知道这个): double shiftAmount = (scrollViewer1.ScrollableWidth / (grid1.ColumnDefinitions.Count - columnsOnScreen)); scrollViewer1.ScrollToHorizontalOffset(column * shiftAmount); 如果我不确切知道他们正在看什么列,但我只是想保持相对位置…… double previousScrollRatio = scrollViewer1.HorizontalOffset / scrollViewer1.ScrollableWidth; //resize grid... scrollViewer1.ScrollToHorizontalOffset(previousScrollRatio * scrollViewer1.ScrollableWidth); 两种方法都不奏效.如果我以滚动条居中缩小,则滚动条将转到最右侧.任何的想法? 可以在上面找到一个最小的代码示例here加上scroll_KeyDown方法. 默认缩放的屏幕截图: 缩小后的屏幕截图,不正确(海军蓝和粉红色方块远离屏幕): 缩小后的屏幕截图,它应该是什么样子: 解决方法
这是一种在放大或缩小时将内容保持在中心的解决方案
//variables to store the offset values double relX; double relY; void scrollViewer1_ScrollChanged(object sender,ScrollChangedEventArgs e) { ScrollViewer scroll = sender as ScrollViewer; //see if the content size is changed if (e.ExtentWidthChange != 0 || e.ExtentHeightChange != 0) { //calculate and set accordingly scroll.ScrollToHorizontalOffset(CalculateOffset(e.ExtentWidth,e.ViewportWidth,scroll.ScrollableWidth,relX)); scroll.ScrollToVerticalOffset(CalculateOffset(e.ExtentHeight,e.ViewportHeight,scroll.ScrollableHeight,relY)); } else { //store the relative values if normal scroll relX = (e.HorizontalOffset + 0.5 * e.ViewportWidth) / e.ExtentWidth; relY = (e.VerticalOffset + 0.5 * e.ViewportHeight) / e.ExtentHeight; } } private static double CalculateOffset(double extent,double viewPort,double scrollWidth,double relBefore) { //calculate the new offset double offset = relBefore * extent - 0.5 * viewPort; //see if it is negative because of initial values if (offset < 0) { //center the content //this can be set to 0 if center by default is not needed offset = 0.5 * scrollWidth; } return offset; } 后面的想法是存储最后一个滚动位置,并在每次更改内容大小时使用它计算新的偏移量,这将使范围发生变化. 只需将ScrollViewer的事件ScrollChanged附加到构造函数等中的此事件处理程序,并将其余部分保留给它. 例如 scrollViewer1.ScrollChanged += scrollViewer1_ScrollChanged; 上述解决方案将确保将电网保持在中心位置,即使是第一次负载也是如此 中心内容的样本 放大了 缩小了 额外 我也尝试为同一个创建一个可附加的行为,因此您不需要连接事件,只需设置属性将启用或禁用该行为 namespace CSharpWPF { public class AdvancedZooming : DependencyObject { public static bool GetKeepInCenter(DependencyObject obj) { return (bool)obj.GetValue(KeepInCenterProperty); } public static void SetKeepInCenter(DependencyObject obj,bool value) { obj.SetValue(KeepInCenterProperty,value); } // Using a DependencyProperty as the backing store for KeepInCenter. This enables animation,styling,binding,etc... public static readonly DependencyProperty KeepInCenterProperty = DependencyProperty.RegisterAttached("KeepInCenter",typeof(bool),typeof(AdvancedZooming),new PropertyMetadata(false,OnKeepInCenterChanged)); // Using a DependencyProperty as the backing store for Behavior. This enables animation,etc... public static readonly DependencyProperty BehaviorProperty = DependencyProperty.RegisterAttached("Behavior",new PropertyMetadata(null)); private static void OnKeepInCenterChanged(DependencyObject d,DependencyPropertyChangedEventArgs e) { ScrollViewer scroll = d as ScrollViewer; if ((bool)e.NewValue) { //attach the behavior AdvancedZooming behavior = new AdvancedZooming(); scroll.ScrollChanged += behavior.scroll_ScrollChanged; scroll.SetValue(BehaviorProperty,behavior); } else { //dettach the behavior AdvancedZooming behavior = scroll.GetValue(BehaviorProperty) as AdvancedZooming; if (behavior != null) scroll.ScrollChanged -= behavior.scroll_ScrollChanged; scroll.SetValue(BehaviorProperty,null); } } //variables to store the offset values double relX; double relY; void scroll_ScrollChanged(object sender,ScrollChangedEventArgs e) { ScrollViewer scroll = sender as ScrollViewer; //see if the content size is changed if (e.ExtentWidthChange != 0 || e.ExtentHeightChange != 0) { //calculate and set accordingly scroll.ScrollToHorizontalOffset(CalculateOffset(e.ExtentWidth,relX)); scroll.ScrollToVerticalOffset(CalculateOffset(e.ExtentHeight,relY)); } else { //store the relative values if normal scroll relX = (e.HorizontalOffset + 0.5 * e.ViewportWidth) / e.ExtentWidth; relY = (e.VerticalOffset + 0.5 * e.ViewportHeight) / e.ExtentHeight; } } private static double CalculateOffset(double extent,double relBefore) { //calculate the new offset double offset = relBefore * extent - 0.5 * viewPort; //see if it is negative because of initial values if (offset < 0) { //center the content //this can be set to 0 if center by default is not needed offset = 0.5 * scrollWidth; } return offset; } } } 启用行为 通过xaml <ScrollViewer l:AdvancedZooming.KeepInCenter="True"> 要么 <Style TargetType="ScrollViewer" x:Key="zoomCenter"> <Setter Property="l:AdvancedZooming.KeepInCenter" Value="True" /> </Style> 或者通过像 scrollViewer1.SetValue(AdvancedZooming.KeepInCenterProperty,true); 要么 AdvancedZooming.SetKeepInCenter(scrollViewer1,true); 通过样式或以编程方式设置属性l:AdvancedZooming.KeepInCenter =“True”内联,以便在任何scrollviewer上启用行为 l:在本例中指的是AdvancedZooming类的命名空间xmlns:l =“clr-namespace:CSharpWPF” (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |