WPFの画像ビューアサンプル

WPFの画像ビューアサンプル。

  • クリックで回転。
  • スライダで回転。

XAML

<Window x:Class="WpfApplication1.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Grid>
<Viewport3D>
<Viewport3D.Camera>
<PerspectiveCamera FieldOfView="50"
  LookDirection="0,-40,300" 
  Position="0,40,-200" UpDirection="0,1,0"/>
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
  <Model3DGroup x:Name="gr">
  <AmbientLight/>
  </Model3DGroup>
  </ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
<Slider Name="slider1" VerticalAlignment="Bottom" 
  ValueChanged="slider1_ValueChanged" Maximum="360" />
<TextBox VerticalAlignment="Top" 
  Text="{Binding ElementName=slider1,Path=Value}" />
</Grid>
</Window>

CS

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;

namespace WpfApplication1
{
  public partial class Window1 : Window
  {
    private MyDoubleValue ta = new MyDoubleValue();
    public Window1()
    {
      InitializeComponent();
      string dir = @"C:\Users\Public\Pictures\Sample Pictures";
      List<ImageBrush> br = new List<ImageBrush>();
      foreach (string f in Directory.GetFiles(dir, "*.jpg"))
        br.Add(new ImageBrush(new BitmapImage(new Uri(f))));
      int[] ii = { 0, 3, 1, 0, 2, 3 };
      Point[] pp = { new Point(1, 1), new Point(0, 1), 
            new Point(1, 0), new Point(0, 0), };
      int n = 9;
      for (int i = 0; i < n; ++i)
      {
        GeometryModel3D gm = new GeometryModel3D();
        gr.Children.Add(gm);
        gm.Material = new DiffuseMaterial(br[i%br.Count]);
        MeshGeometry3D mg = new MeshGeometry3D();
        gm.Geometry = mg;
        double r = 2 * Math.PI * i / n;
        double x = Math.Sin(r), x1 = x * 100, x2 = x * 20;
        double z = Math.Cos(r), z1 = z * 100, z2 = z * 20;
        mg.Positions.Add(new Point3D(x1 - z2,  0, z1 + x2));
        mg.Positions.Add(new Point3D(x1 + z2,  0, z1 - x2));
        mg.Positions.Add(new Point3D(x1 - z2, 30, z1 + x2));
        mg.Positions.Add(new Point3D(x1 + z2, 30, z1 - x2));
        foreach (int j in ii) mg.TriangleIndices.Add(j);
        foreach (Point p in pp) mg.TextureCoordinates.Add(p);
      }
      gr.Transform = new RotateTransform3D();
      Binding bnd = new Binding();
      bnd.Source = ta;
      bnd.Path = new PropertyPath("MyValue");
      slider1.SetBinding(Slider.ValueProperty, bnd);
      MouseDown += new MouseButtonEventHandler(Window1_MouseDown);
    }
    void Window1_MouseDown(object sender, MouseButtonEventArgs e)
    {
      DoubleAnimation da1 = new DoubleAnimation(
        slider1.Value, slider1.Value + 40 - slider1.Value % 40, 
        new Duration(TimeSpan.FromSeconds(0.3)));
      ta.BeginAnimation(MyDoubleValue.MyValueProperty, da1);
    }
    private void slider1_ValueChanged(object sender, 
      RoutedPropertyChangedEventArgs<double> e)
    {
      RotateTransform3D rt = (RotateTransform3D)gr.Transform;
      rt.Rotation = new QuaternionRotation3D(
        new Quaternion(new Vector3D(0, 1, 0), slider1.Value));
    }
  }
  public class MyDoubleValue : UIElement
  {
    public static readonly DependencyProperty MyValueProperty
      = DependencyProperty.Register("MyValue", typeof(double), 
      typeof(MyDoubleValue), new PropertyMetadata(0.0, cb1, cb2));
    private static void cb1(DependencyObject d, DependencyPropertyChangedEventArgs w) { }
    private static object cb2(DependencyObject d, object o)
    {
      double dd = (double)o;
      return dd % 360;
    }
  }
}



解説

  • 画像は、サンプルから9個とってきている。(PathはVistaのもの)
  • 3Dモデルは、プログラムで生成している。ただの四角だけど。
  • Sliderを動かすと、絵を回転する。絵のTransfrormを予め、RotateTransform3Dにしておき、そのRotation(QuaternionRotation3D)を置き換えている。
  • DoubleAnimationでSliderを直接アニメーションさせると、スライダが手動で動かないので、アニメーション用データ(MyDoubleValue)を作成して使っている。このMyValueをアニメーションさせている。
  • プログラムで、MyValueとスライダをBindingしている。
  • TextBoxはXAMLでSliderとBindingしている。
  • MyDoubleValueの値は角度なので、360のModを取るようにCoerceValueCallback を定義している。
  • StoryBoardをプログラムで追加するには、Storyboard.SetTargetProperty を使えばよい。