WPF使用按钮和滑块放大和缩小

时间:2015-02-18 01:50:10

标签: c# wpf xaml

有没有办法将按钮(如果这是正确的单词)链接到滑块?我正在尝试创建一个能够放大图像的图像查看器。我能够通过使用Tick设置为.25,.50一直到2的滑块来实现这一目标,这将是25%到200%的图像比例。但我还想实现一个放大和缩小按钮(就像Microsoft Paint一样),点击它时会使滑块箭头移动到下一个或上一个刻度线(取决于放大或缩小),从而增加或减少图像比例25%。我是WPF的新手,所以我不熟悉我可以使用的所有属性,但我读到我可以通过使用Storyboard为其设置动画。除了使用故事板之外还有另一种方法可以完成我打算做的事情。现在我的ZoomIn功能只是一个假人,因为我还在研究如何做到这一点,因此引发了异常。我提前感谢您的帮助。

XAML:

<Window x:Class="kazoom.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Zoom Window">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="auto"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition Width="auto"/>
    </Grid.ColumnDefinitions>
    <ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
        <Grid x:Name="GridLoadedImage" HorizontalAlignment="Left" VerticalAlignment="Top">
            <Grid.LayoutTransform>
                <ScaleTransform ScaleX="{Binding ElementName=slider1, Path=Value}" ScaleY="{Binding ElementName=slider1, Path=Value}"/>
            </Grid.LayoutTransform>
            <Image Name="loaded" Grid.Column="1" Source="image/Desert.jpg" Stretch="Fill" />
        </Grid>
    </ScrollViewer>
    <StackPanel Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center">
        <Button x:Name="Import" Width="93" Height="20" Content="Import" Margin="10" />
        <Button x:Name="ZoomIn" Width="93" Height="20" Content="ZoomIn" Margin="10" />
    </StackPanel>

    <Slider Name="slider1"
            Grid.Row="1"
            Maximum="2"
            Minimum=".15"
            IsMoveToPointEnabled="True"
            TickPlacement="BottomRight"
            TickFrequency="2"
            Ticks=".15,.30,.45,.60,.75,1,1.15,1.30,1.45,1.60,1.75,2"
            Width="200"
            Margin="20"
            HorizontalAlignment="Center"
            SelectionStart="1" IsSnapToTickEnabled="True"/>

</Grid>
</Window>

代码背后:

using Microsoft.Win32;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace kazoom
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {

    public MainWindow()
    {
        InitializeComponent();
        ZoomIn.AddHandler(Button.ClickEvent, new RoutedEventHandler(ZoomIn_Click));
        Import.AddHandler(Button.ClickEvent, new RoutedEventHandler(Import_Click));

    }

    private void Import_Click(object sender, RoutedEventArgs e)
    {
        OpenFileDialog image = new OpenFileDialog();
        image.FileName = "Picture";
        image.Filter = "Pictures (*.jpeg)|*.jpg";

        if (image.ShowDialog() == true)
        {
            loaded.Source = new BitmapImage(new Uri(image.FileName));
        }
    }
    private void ZoomIn_Click(object sender, RoutedEventArgs e)
    {
        throw new System.NotImplementedException();
    }
}

}

3 个答案:

答案 0 :(得分:0)

我承认,我不知道解决这个问题的最佳方法是什么。但是,我们会想到一个相当明显的解决方案:将值绑定到int属性,该属性是当前的滴答索引,使用转换器在滑块值和索引之间进行映射,然后让按钮调整{ {1}}财产。例如......

转换器:

int

在设置目标时,上述转换器只使用索引来查找刻度值。在反方向上,它查找当前滑块值的最近刻度值,并将滑块值映射到该刻度值的索引(在您的情况下,class IndexToSliderValueConverter : DependencyObject, IValueConverter { public Slider Slider { get { return (Slider)GetValue(SliderProperty); } set { SetValue(SliderProperty, value); } } public static readonly DependencyProperty SliderProperty = DependencyProperty.Register( "Slider", typeof(Slider), typeof(IndexToSliderValueConverter)); public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (Slider != null && Slider.Ticks != null && Slider.Ticks.Count > 0 && value is int) { int intValue = (int)value; if (intValue >= 0 && intValue < Slider.Ticks.Count) { return Slider.Ticks[(int)value]; } throw new ArgumentOutOfRangeException("value must be valid tick index"); } return Binding.DoNothing; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (Slider != null && Slider.Ticks != null && Slider.Ticks.Count > 0 && value is double) { double doubleValue = (double)value, minDifference = double.MaxValue; int index = -1; for (int i = 0; i < Slider.Ticks.Count; i++) { double difference = Math.Abs(doubleValue - Slider.Ticks[i]); if (difference < minDifference) { index = i; minDifference = difference; } } return index; } return Binding.DoNothing; } } 设置为IsSnapToTickEnabled,滑块值应始终与刻度值完全相等,但此实现比假设始终如此的实现更强大。

这里的问题是,虽然转换器需要访问实际的true对象(或至少它的Slider集合),但我不知道有任何方法可以传递实例转换器用于实际转换方法的对象。

Ticks的{​​{1}}属性不是依赖属性,因此它本身无法绑定。而且我无法在其资源声明中将ConverterParameter元素绑定到转换器,因为即使我将Binding命名,生成的字段的值仍为Slider在创建转换器对象时。

所以这部分内容有点像黑客。您会注意到我确实在转换器上实现了一个依赖属性,以获取Slider值(如果我确实找到了一种基于XAML的方法来绑定正确的值)。现在,我只是在窗口的代码隐藏中设置该值。

顺便说一下,这看起来像这样:

null

这里,有一个表示tick指数的依赖属性。在构造函数中,我通过从资源字典中检索对象并直接分配属性,将Slider对象引用分配给转换器的public partial class MainWindow : Window { public static readonly DependencyProperty SliderIndexValueProperty = DependencyProperty.Register( "SliderIndexValue", typeof(int), typeof(MainWindow)); public int SliderIndexValue { get { return (int)GetValue(SliderIndexValueProperty); } set { SetValue(SliderIndexValueProperty, value); } } public MainWindow() { InitializeComponent(); ((IndexToSliderValueConverter)Resources["indexToSliderValueConverter1"]).Slider = slider1; SliderIndexValue = 2; } private void DownButton_Click(object sender, RoutedEventArgs e) { if (SliderIndexValue > 0) { SliderIndexValue--; } } private void UpButton_Click(object sender, RoutedEventArgs e) { if (SliderIndexValue < slider1.Ticks.Count - 1) { SliderIndexValue++; } } } 属性。不是很优雅,但它让事情与我需要的方式联系在一起。

我还添加了对tick指数属性的赋值,就像一个&#34;概念证明&#34;。当然,它的工作原理也足够证据。 :)

最后,窗口的XAML:

slider1

只需要几个按钮就可以向上或向下滑动滑块,滑块本身和Slider来显示实际的刻度指数属性值(再次,为了说明...你显然没有&#39;在你自己的程序中需要它。)

您应该能够在自己的代码中使用与上述相同的技术。

记录:我不知道基于<Window x:Class="TestSO28574624SliderWithUpDownButtons.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TestSO28574624SliderWithUpDownButtons" x:Name="root" Title="MainWindow" Height="350" Width="525"> <Window.Resources> <local:IndexToSliderValueConverter x:Key="indexToSliderValueConverter1"/> </Window.Resources> <StackPanel> <StackPanel Orientation="Horizontal"> <StackPanel.Resources> <Style TargetType="Button"> <Setter Property="Margin" Value="3" /> </Style> </StackPanel.Resources> <Button Content="Down" Click="DownButton_Click"/> <Button Content="Up" Click="UpButton_Click" /> </StackPanel> <Slider x:Name="slider1" Minimum="0.15" Maximum="2" IsSnapToTickEnabled="True" Ticks="0.15,0.3,0.45,0.6,0.75,1,1.15,1.3,1.45,1.6,1.75,2" Value="{Binding ElementName=root, Path=SliderIndexValue, Converter={StaticResource indexToSliderValueConverter1}}"/> <TextBlock Text="{Binding ElementName=root, Path=SliderIndexValue}"/> </StackPanel> </Window> 的实现如何工作。我不清楚TextBlock如何获得对Storyboard属性的访问权限以及相对于当前Storyboard值的索引,以便在调整它时有用。但是,我自己对WPF很陌生。也许其他人会在这些方面有一些具体的建议。

与此同时,我确信上述工作。 :)

答案 1 :(得分:0)

您只需要通过滑块的Ticks集合进行枚举,找到当前滑块值之前或之后的下一个刻度值(取决于您是放大还是缩小)。

private void ZoomIn_Click(object sender, RoutedEventArgs e)
{
    slider1.Value = slider1.Ticks.Select(x => (double?) x)
        .FirstOrDefault(x => x > slider1.Value) ?? slider1.Value;
}

private void ZoomOut_Click(object sender, RoutedEventArgs e)
{
    slider1.Value = slider1.Ticks.Select(x => (double?) x)
        .LastOrDefault(x => x < slider1.Value) ?? slider1.Value;
}

这假定Ticks集合中的值按升序存储。在每个OrderBy之前添加Select方法调用可以防止值处于不同的顺序。

答案 2 :(得分:0)

我只需简单地将slider1值递增和递减.15并通过添加1.0就可以找到解决方案,它也能够进行100%缩放。按钮和滑块都相应地使用此解决方案,因为每次按下缩放按钮也会移动滑块,这是我正在寻找的效果。以下是代码:

 private void GenericZoomHandler(object sender, RoutedEventArgs e)
    {
        if (sender.Equals(ZoomOut))   //if sender is ZoomOut object
        {
            slider1.Value -= .15;     //decrement by 15%
        }
        else if (sender.Equals(ZoomIn))   //if sender is ZoomIn object
        {
            slider1.Value += .15;    //increment by 15%
        }
        else if (sender.Equals(Zoom100))   //if sender is Zoom100 object
        {
            slider1.Value = 1.0;        //return to original size of image     (100%)
        }

    }