ScrollViewer中的Silverlight Canvas大小调整

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ScrollViewer中的Silverlight Canvas大小调整相关的知识,希望对你有一定的参考价值。

我正在用C#制作一个Silverlight 4网站。在其中一个页面中,我希望两个面板彼此相邻。左边是地图控件,右边是图像。这很容易,但我也希望能够点击图像并将PushPin保留为对象(如地图),因此我将图像放在画布上并绘制圆圈。问题是图像可能相当大,我需要能够滚动图像。我尝试了几种不同的方法来实现这一点,但到目前为止还没有运气。

以下帖子的答案似乎是要走的路,但必须有Silverlight的更新打破它:WPF: How to make canvas auto-resize?

一个similar solution建议从头开始制作Canvas,但我遇到了同样的问题。

我的大部分尝试都是在屏幕上尽可能多地显示图像,但没有滚动条(仍然是灰色的)或者图像加载时页面只是白色。

以下是我当前选择要加载的图像的方式:

        OpenFileDialog dialog = new OpenFileDialog();
        dialog.Filter = "Image Files (*.png, *.jpg)|*.jpg;*.png";
        if(dialog.ShowDialog() == true) {
            BitmapImage bitmap = new BitmapImage();
            FileStream stream = dialog.File.OpenRead();
            bitmap.SetSource(stream);
            TheImage.Source = bitmap;
        }
答案

可能有一个更好的解决方案,但这应该做的伎俩。

我创建了一个小的固定大小的ScrollViewer,它包含一个Canvas和一个图像。然后我使用一种行为来修改画布的大小以匹配图像的大小。该行为还处理ImageOpened事件,以便在打开图像后设置正确的图像大小。

这是xaml:

<ScrollViewer Width="200" Height="200" HorizontalScrollBarVisibility="Auto">
    <Canvas x:Name="TheCanvas">
        <Image x:Name="TheImage">
            <i:Interaction.Behaviors>
                <Views:ResizeCanvasBehaviour Canvas="{Binding ElementName=TheCanvas}"/>
            </i:Interaction.Behaviors>
        </Image>
    </Canvas>
</ScrollViewer> 

一定要将i声明为xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity",并且b匹配放置行为的命名空间。

以下是行为的代码:

public class ResizeCanvasBehaviour : Behavior<Image>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.SizeChanged += AssociatedObject_SizeChanged;
        AssociatedObject.ImageOpened += AssociatedObject_ImageOpened;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.SizeChanged -= AssociatedObject_SizeChanged;
        AssociatedObject.ImageOpened -= AssociatedObject_ImageOpened;
    }

    private void AssociatedObject_ImageOpened(object sender, RoutedEventArgs e)
    {
        BitmapSource bitmapSource = AssociatedObject.Source as BitmapSource;
        if (bitmapSource == null)
        {
            return;
        }

        AssociatedObject.Width = bitmapSource.PixelWidth;
        AssociatedObject.Height = bitmapSource.PixelHeight;

        Resize();
    }

    private void AssociatedObject_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        Resize();
    }

    public Canvas Canvas
    {
        get { return GetValue(CanvasProperty) as Canvas; }
        set { SetValue(CanvasProperty, value); }
    }

    public static readonly DependencyProperty CanvasProperty = DependencyProperty.Register(
        "Canvas",
        typeof(Canvas),
        typeof(ResizeCanvasBehaviour),
        new PropertyMetadata(null, CanvasPropertyChanged));

    private static void CanvasPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ResizeCanvasBehaviour)d).OnCanvasPropertyChanged();
    }

    private void OnCanvasPropertyChanged()
    {
        if (Canvas != null)
        {
            Resize();
        }
    }

    private void Resize()
    {
        if ((AssociatedObject != null) && (Canvas != null))
        {
            Canvas.Width = AssociatedObject.ActualWidth;
            Canvas.Height = AssociatedObject.ActualHeight;
        }
    }
}

要加载图像,请执行以下操作。我在代码背后为速度做了这个,但理想情况下你应该把它放在一个视图模型中然后数据绑定xaml中的图像Source属性:

BitmapImage bi = new BitmapImage();
bi.UriSource = new Uri("http://farm7.static.flickr.com/6149/5942401995_a5a3fd3919_z.jpg");
TheImage.Source = bi;
另一答案

事实证明我需要做的最小的事情是将画布的宽度和高度设置为BitmapImage实例的PixelWidth和PixelHeight。

这就是Paul用他的解决方案做的事情(以更复杂的方式),但由于某种原因,在本地加载图像时不会调用resize事件处理程序。

我尝试了几种不同的建议解决方案,但我从未得到过我想要的结果。这是唯一可行的解​​决方案。

以上是关于ScrollViewer中的Silverlight Canvas大小调整的主要内容,如果未能解决你的问题,请参考以下文章

分析 Silverlight 4

silverlight控件阴影效果示例

Scrollviewer 中的扩展器:折叠扩展器后 Scrollviewer 不收缩

如何以编程方式将垂直滚动条添加到组合框

使 Scrollviewer 填充 DockPanel 中的可用空间

在进行缩放手势时替换 ScrollViewer 中的图像