gpt4 book ai didi

使用 ScrollViewer 和动态拉伸(stretch)的 Wpf 滚动图像

转载 作者:行者123 更新时间:2023-12-04 21:55:27 24 4
gpt4 key购买 nike

我正在开发一个简单的图像查看器应用程序。我根据 ViewModel 属性控制绑定(bind)上的 Stretch 属性。

当我更改基于绑定(bind)到 ViewModel 的“Combobox”的 Stretch 属性时会出现问题,并且在使用“UniformToFill”时图像会“切断”宽图像的角。因此要使用 ScrollViewer 来滚动图像内容。

问题是 ScrollViewer 似乎没有显示滚动条让我能够滚动。

WPF 标记:

<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

<!-- Other Grids removed -->

<Grid Name="Container" Grid.Column="2" Grid.Row="0" Grid.RowSpan="2">
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Image Source="{Binding SelectedPhoto.Value.Image}"
Stretch="{Binding ImageStretch}" Name="PhotoImage" />
</ScrollViewer>
</Grid>

我知道如果我为 ScrollViewer 和 Image 设置固定的高度和宽度,它就会起作用。但我想动态地做:

  • ScrollView 的高度和宽度来自父“Grid(Contaioner)”控件。
  • 图像本身具有高度和宽度,但在该计算中考虑了拉伸(stretch)。

可以用 ActualHeight、ActualWidth 来解决吗?还有一个依赖属性?

最佳答案

这几乎是不可能的,或者我应该说期望 ScrollViewer 使用 Stretch = UniformToFill 知道图像的边界没有多大意义。根据MSDN :

UniformToFill: The content (your Image) is resized to fill the destination dimensions (window or grid) while it preserves its native aspect ratio. If the aspect ratio of the destination rectangle differs from the source, the source content is clipped to fit in the destination dimensions (Therefore the image will be cutted off).

所以我认为我们真正需要的是使用 Uniform + Proper Scaling 而不是 UniformToFill

解决方案是当 Stretch 设置为 UniformToFill 时,它必须设置为 Uniform 然后 Image.Width = image actual width * scalingParamImage.Height= 图片实际高度 * scalingParam,其中 scalingParam = Grid.Width(或 Height)/图片实际宽度(或 Height)。这样,ScrollViewer 边界将与图像缩放后的大小相同。

我已经提供了一个可行的解决方案来给你一个想法,我不确定它是否适合你的情况,但这里是:

首先,我为图像定义了一个简单的 View 模型:

    public class ImageViewModel: INotifyPropertyChanged
{

// implementation of INotifyPropertyChanged ...

private BitmapFrame _bitmapFrame;

public ImageViewModel(string path, Stretch stretch)
{
// determining the actual size of the image.
_bitmapFrame = BitmapFrame.Create(new Uri(path), BitmapCreateOptions.DelayCreation, BitmapCacheOption.None);

Width = _bitmapFrame.PixelWidth;
Height = _bitmapFrame.PixelHeight;
Scale = 1;
Stretch = stretch;
}

public int Width { get; set; }
public int Height { get; set; }

double _scale;
public double Scale
{
get
{
return _scale;
}
set
{
_scale = value;
OnPropertyChanged("Scale");
}
}
Stretch _stretch;
public Stretch Stretch
{
get
{
return _stretch;
}
set
{
_stretch = value;
OnPropertyChanged("Stretch");
}
}
}

在上面的代码中,BitmapFrame 用于确定图像的实际大小。然后我在我的 Mainwindow(或主视图模型)中做了一些初始化:

    // currently displaying image
ImageViewModel _imageVm;
public ImageViewModel ImageVM
{
get
{
return _imageVm;
}
set
{
_imageVm = value;
OnPropertyChanged("ImageVM");
}
}

// currently selected stretch type
Stretch _stretch;
public Stretch CurrentStretch
{
get
{
return _stretch;
}
set
{
_stretch = value;
//ImageVM should be notified to refresh UI bindings
ImageVM.Stretch = _stretch;
OnPropertyChanged("ImageVM");
OnPropertyChanged("CurrentStretch");
}
}

// a list of Stretch types
public List<Stretch> StretchList { get; set; }
public string ImagePath { get; set; }
public MainWindow()
{
InitializeComponent();
DataContext = this;

// sample image path
ImagePath = @"C:\Users\...\YourFile.png";

StretchList = new List<Stretch>();
StretchList.Add( Stretch.None);
StretchList.Add( Stretch.Fill);
StretchList.Add( Stretch.Uniform);
StretchList.Add( Stretch.UniformToFill);

ImageVM = new ImageViewModel(ImagePath, Stretch.None);

CurrentStretch = StretchList[0];

}

我的 Xaml 看起来像这样:

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" >
<Grid.Resources>
<local:MultiConverter x:Key="multiC"/>
</Grid.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Image Source="{Binding ImagePath}" Name="PhotoImage">
<Image.Stretch>
<MultiBinding Converter="{StaticResource multiC}">
<Binding Path="ImageVM" />
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualWidth"/>
<Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="ActualHeight"/>
</MultiBinding>
</Image.Stretch>
<Image.LayoutTransform>
<ScaleTransform ScaleX="{Binding ImageVM.Scale}" ScaleY="{Binding ImageVM.Scale}"
CenterX="0.5" CenterY="0.5" />
</Image.LayoutTransform>
</Image>
</ScrollViewer>
</Grid>
<ComboBox Grid.Row="2" Grid.Column="0" ItemsSource="{Binding StretchList}" SelectedItem="{Binding CurrentStretch}" DisplayMemberPath="."/>
</Grid>

如您所见,我使用了一个带有 3 个参数的多值转换器:当前 ImageView 模型和窗口宽度和高度。此参数用于计算图像填充区域的当前大小。我还使用 ScaleTransform 将该区域缩放到计算的大小。这是多值转换器的代码:

public class MultiConverter : IMultiValueConverter
{
public object Convert(
object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] is ImageViewModel)
{
var imageVm = (ImageViewModel)values[0];

// if user selects UniformToFill
if (imageVm.Stretch == Stretch.UniformToFill)
{
var windowWidth = (double)values[1];
var windowHeight = (double)values[2];

var scaleX = windowWidth / (double)imageVm.Width;
var scaleY = windowHeight / (double)imageVm.Height;

// since it's "uniform" Max(scaleX, scaleY) is used for scaling in both horizontal and vertical directions
imageVm.Scale = Math.Max(scaleX, scaleY);

// "UniformToFill" is actually "Uniform + Proper Scaling"
return Stretch.Uniform;
}
// if user selects other stretch types
// remove scaling
imageVm.Scale = 1;
return imageVm.Stretch;
}
return Binding.DoNothing;
}

public object[] ConvertBack(
object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}

关于使用 ScrollViewer 和动态拉伸(stretch)的 Wpf 滚动图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31399980/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com