c# - 自动调整“ListView”中图像的缩放以适合所有人,即在没有滚动条的情况下最大化它们的大小
问题描述
我有一个视图IntroView
,其中包含一个ListView
,其中包含图像,并且可以缩放(调整每个图像的大小(或更具体地说是UserControl
)),由依赖属性ThumbZoom
(在后面的代码中IntroView
)确定。
我正在尝试自动调整该ThumbZoom
值,以便里面的所有图像都适合ListView
尺寸(它自己在一个可调整大小的窗口内)。
类似问题的这个选项不起作用:当溢出(垂直滚动条可见)发生时,切换可见性只会使滚动条消失,但不会改变ThumbZoom
. 如何做到这一点?
的 xamlIntroView
尤其具有:
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" Grid.Column="0" BorderThickness="0"
Background="Transparent"
IsSynchronizedWithCurrentItem="True"
MouseDoubleClick="Control_OnMouseDoubleClick"
ItemsSource="{Binding RawImagesCollectionView}" SelectedItem="{Binding SelectedImage}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate DataType="shutterLib:RawImageViewModel">
<intro:RawImageControl/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
并且在依赖属性后面的代码中有ThumbZoom
:
public double ThumbZoom
{
get { return (double) GetValue(ThumbZoomProperty); }
set { SetValue(ThumbZoomProperty, value); }
}
public static readonly DependencyProperty ThumbZoomProperty =
DependencyProperty.Register("ThumbZoom", typeof(double), typeof(IntroView),
new PropertyMetadata(_minZoom));
被UserControl
调用的接收图像,如下所示:
<UserControl x:Class="Senso.ShutterModeler.UI.Intro.RawImageControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ui="clr-namespace:Senso.ShutterModeler.UI"
xmlns:shutterLib="clr-namespace:ShutterLib;assembly=ShutterLib"
d:DataContext="{d:DesignInstance Type=shutterLib:RawImageViewModel, IsDesignTimeCreatable=True}"
mc:Ignorable="d"
d:DesignHeight="200" d:DesignWidth="400">
<Grid Margin="5" MinWidth="100" MinHeight="100">
<Rectangle Fill="DimGray"
MaxWidth="{Binding ThumbZoom, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ui:IntroView}}}"
MaxHeight="{Binding ThumbZoom, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ui:IntroView}}}">
<Rectangle.Effect>
<DropShadowEffect BlurRadius="11" Color="{StaticResource DropShadow}" />
</Rectangle.Effect>
</Rectangle>
<Viewbox
MaxWidth="{Binding ThumbZoom, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ui:IntroView}}}"
MaxHeight="{Binding ThumbZoom, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ui:IntroView}}}">
<Image Stretch="Uniform" Source="{Binding Vignette, IsAsync=false}" MouseMove="Vignette_OnMouseMove" />
</Viewbox></Grid></UserControl>
要解决的问题(有几个条件:图像周围没有边距(为了简化),以及 1:2 的纵横比)是这样放置的:
在绘制之后,有这个方面(对于给定的T
和):Ha
Wa
ScrollViewer
这是个好消息:这个最小值是存在的,并且可以通过二等分来解决。在解决方案的左侧,图像的大小太小而无法填充ListView
,跳跃对应于每行图像数量的变化。在解决方案的右侧,图像的大小太大并触发垂直滚动条的出现。
不幸的是,根据 的方面 (ActualWidth
和ActualHeight
) ScrollViewer
,解决方案仅有时在视觉上是正确的。似乎ScrollViewer
嵌入的大小ListView
有一个方面与.的视觉方面不匹配ListView
。在纵横比条件Ha
Wa
(只有几个像素(~5),增量约为 70 像素)。
到目前为止我不明白。这是我需要帮助的地方。
我用于new ScrollViewer {RenderSize = new Size(1558, 1281) }
情节。
解决问题的代码是:
private double _minZoom = 200.0;
private double _maxZoom = 900.0;
private int _totalCount = 17; // total number of images to show in listview.
/// <summary>
/// Size of semi-range of solution.
/// </summary>
public double BallRadius { get; set; } = 1e-6;
/// <summary>
/// Number of steps needed to find optimal zoom.
/// </summary>
public int StepCount { get; protected set; }
/// <summary>
/// Best zoom, where images are a big as possible, while no scrollbar appears.
/// </summary>
public double ZoomFitall => SolveMin(x => Deriv(DistZZbis, x));
/// <summary>
/// Solve minimum of func in [_minZoom, _maxZoom] with bisection method.
/// </summary>
/// <param name="func"></param>
/// <returns>optimal zoom</returns>
public double SolveMin(Func<double, double> func)
{
int stepCount = 0;
double l = _minZoom;
double r = _maxZoom;
bool IsMinInThisRange(double a, double b) => func(a) * func(b) < 0;
double GetMiddle(double a, double b) => (a + b) / 2.0;
double IntervalWidth(double a, double b) => Abs(a - b);
while (IntervalWidth(l, r) > BallRadius)
{
stepCount++;
double m = GetMiddle(l, r);
if (IsMinInThisRange(l, m))
r = m;
else
l = m;
}
StepCount = stepCount;
return l;
}
/// <summary>
/// Calculate derivative of <c>func<c/> at <c>x0</c> over interval of <c>2dx</c>.
/// </summary>
/// <param name="func">for fitall, use DistZZbis</param>
/// <param name="x0">deriveative at x0</param>
/// <param name="dx">infinitesimal semi-interval over x</param>
/// <returns></returns>
public double Deriv(Func<double, double> func, double x0, double dx = 1e-6)
{
var left = func(x0 - dx);
var right = func(x0 + dx);
return right - left;
}
/// <summary>
/// Calculate distance between <c>zoom</c> and <c>zoom bis</c> as described in FindFitAll.
/// </summary>
/// <param name="z"></param>
/// <returns></returns>
public double DistZZbis(double z) => Abs(z - Zbis(z));
/// <summary>
/// Calculate zoom bis.
/// </summary>
/// <param name="z"></param>
/// <returns></returns>
private double Zbis(double z) => 2 * _scroll.ActualHeight / Ceiling(_totalCount / Floor(_scroll.ActualWidth / z));
解决方案
推荐阅读
- visual-studio - 是在不同的层中复制多个项目文件,还是在创建 Docker 映像时一次性复制更好?
- javascript - 如何在数字输入字段中添加逗号以获取多个重新编码
- swift - 从集合视图重新加载数据时的多个视图
- azure-sql-database - Azure SQL 高级数据安全 (ADS) 和安全中心定价
- leakcanary - 了解 LeakCanary 内存泄漏堆栈跟踪
- c++ - 如何使用new创建指向结构的指针数组?
- html - 为什么我不能使用 getBoundingClientRect()?
- angularjs - 如何使用来自不同控制器的参数触发过滤功能
- xml - 将 xml 节点转换为 typescript 定义的类型
- kubernetes - HAProxy 2.0.2 不会为服务中的所有 pod 创建“srv”