WPF Layout & Image异步加载

WPF Layout

在窗体布局中,为了适应不同的分辨率时,我们常常用到神奇的Viewbox控件帮助我们.

layout1

 

XAML:

      <Viewbox>
            <Canvas Width="980" Height="435" x:Name="canvas">
                <Canvas.Background>
                    <ImageBrush ImageSource="images\hhbanner.jpg"></ImageBrush>
                </Canvas.Background>
                
                <Label Canvas.Left="200"  Content="一口盐水喷死让你还无所畏" FontSize="24"  Name="label1" />
                <Image  Height="150" Name="image1" Stretch="Fill" Width="200" Source="/WPFLayoutTest;component/images/fzz.jpg" />
            </Canvas>
        </Viewbox>

 

如上窗体布局中,Viewbox 里放入了一个Lable,一个Image,当窗体拉伸时,Lable和Image将自动缩放.

那么如何让窗体放大时,方先生的形象不随着韩同学的形象一起放大呢?

了解一下WPF Layout System,WPF 提供了一个两个自定义接口(MeasureOverrideArrangeOverride)给用户自定义Layout.
详细解释参照:

WPF/Silverlight Layout 系统概述——Measure

 

实现如上需求,我们自定义一个Canvas,在重写其ArrangeOverride 方法,当发现子控件是Image时,按照一定比例缩放:

   <Viewbox>
            <my:CustomCanvas Width="980" Height="435" x:Name="canvas">
                <my:CustomCanvas.Background>
                    <ImageBrush ImageSource="images\hhbanner.jpg"></ImageBrush>
                </my:CustomCanvas.Background>
                
                <Label Canvas.Left="200"  Content="一口盐水喷死让你还无所畏" FontSize="24"  Name="label1" />
                <Image  Height="150" Name="image1" Stretch="Fill" Width="200" Source="/WPFLayoutTest;component/images/fzz.jpg" />
            </my:CustomCanvas>
        </Viewbox>

在Window Size Change 时计算还原要的缩放比率

        private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (defaultWinSize == Size.Empty)
                return;
            var newSize = e.NewSize;
            var scaleX = defaultWinSize.Width / newSize.Width;
            var scaleY = defaultWinSize.Height / newSize.Height;

            this.canvas.SetScale(scaleX, scaleY);

        }
 public class CustomCanvas : Canvas
    {
        private double scaleX = 1;
        private double scaleY = 1;

        public void SetScale(double x, double y)
        {
            this.scaleX = x;
            this.scaleY = y;
            this.InvalidateArrange();
        }

        /// <summary>
        /// 重写ArrangeOverride 方法,使Image不随着外面的Viewbox缩放而缩放.
        /// </summary>
        /// <param name="arrangeSize"></param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            Transform scaleTransform = new ScaleTransform(this.scaleX, this.scaleY);
            foreach (UIElement uIElement in base.InternalChildren)
            {
                if (uIElement != null)
                {
                    double x = 0.0;
                    double y = 0.0;
                    double left = Canvas.GetLeft(uIElement);
                    if (!DoubleUtil.IsNaN(left))
                    {
                        x = left;
                    }
                    else
                    {
                        double right = Canvas.GetRight(uIElement);
                        if (!DoubleUtil.IsNaN(right))
                        {
                            x = arrangeSize.Width - uIElement.DesiredSize.Width - right;
                        }
                    }
                    double top = Canvas.GetTop(uIElement);
                    if (!DoubleUtil.IsNaN(top))
                    {
                        y = top;
                    }
                    else
                    {
                        double bottom = Canvas.GetBottom(uIElement);
                        if (!DoubleUtil.IsNaN(bottom))
                        {
                            y = arrangeSize.Height - uIElement.DesiredSize.Height - bottom;
                        }
                    }
                    if (uIElement is Image)
                    {
                        uIElement.RenderTransform = scaleTransform;
                    }
                    uIElement.Arrange(new Rect(new Point(x, y), uIElement.DesiredSize));
                }
            }
            return arrangeSize;

        }
    }


Demo Code: 下载

 

Image 异步加载:

WPF UI 上的东西,不是太容易异步,常用的Backgroud,Dispatch.Invoke 之类的方法,只能对于所操作代码中没有UI相关的才能真的异步,从而不堵住UI线程.

一下加载很多图片,很容易卡住UI,下面有个方案很好解决了异步加载图片的问题,

Loading Images Asynchronously in WPF
http://dotnetlearning.wordpress.com/2011/01/27/loading-images-asynchronously-in-wpf/

Code 下载

效果:

  • 可自定义加载的动画,或不使用动画
  • 可自定义加载图片失败时效果

posted on 2012-08-01 11:10  Haozes  阅读(2910)  评论(1编辑  收藏  举报