ブログ用 画像ユーティリティ ⑤ ユーザーコントロール
以下のようにXAMLで記述できるユーザーコントロール VgaImageUC を作成します。
<local:VgaImageUC x:Name="myVgaImage" Grid.Row="1"
MouseLeftButtonDown="UC_MouseLeftButtonDown"
MouseMove="UC_MouseMove" />
このユーザーコントロールの役割は①要件と戦略で説明したように、以下の4つです。
- Vgaサイズ画像の作成と表示
- モザイク画像の作成と、クリップ表示
- 上記2つの画像の合成画像の作成
- jpgにエンコードして出力
ユーザーコントロールは UserContrl クラスを継承した具象クラスです(これに対し、カスタムコントロールはControlを継承した具象クラス)。Visual Studio のソリューションエクスプローラーで追加→新しい項目から、以下のダイアログで[ユーザーコントロール(WPF)]を選ぶと、XAMLとコードビハインドのテンプレートを生成してくれます。
2つの画像を表示するXAMLを記述します。Mosaique画像はVisibilutyをHiddenにして、ぼかしをかけないRenderOptionであるNearestNeighborにします。
<UserControl x:Class="ImageShrinker.VgaImageUC"
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
>
<Border Name="myPlaceholder" Width="640" Height="480">
<Canvas Name="myCanvas">
<Image Canvas.Left="0" Canvas.Top="0" Name="myImage" />
<Image Canvas.Left="0" Canvas.Top="0" Name="myMosaique"
Visibility="Hidden"
RenderOptions.BitmapScalingMode="NearestNeighbor" />
</Canvas>
</Border>
</UserControl>
VgaImageUCユーザーコントロールでは、ファイル名(FileName)とクリップ矩形(ClipRect)が変更されたら、自動的に画像を表示させたいので、この2つのプロパティをDependencyPropertyとして定義します。
public string FileName
{
get { return (string)GetValue(FileNameProperty); }
set { SetValue(FileNameProperty, value); }
}
public static DependencyProperty FileNameProperty =
DependencyProperty.Register("FileName", typeof(string),
typeof(VgaImageUC), new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnFileNameChanged)));
/// <summary>
/// プロパティ変更のコールバック
/// </summary>
private static void OnFileNameChanged(
DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
VgaImageUC control = (VgaImageUC)obj;
control.UpdateImage();
}
private readonly int _vgaWidth = 640;
private readonly int _scale = 20;
/// <summary>
/// 画像の更新
/// </summary>
private void UpdateImage()
{
BitmapImage bi =
CreateSmallImage(_vgaWidth, this.FileName);
myImage.Source = bi;
myImage.Width = bi.PixelWidth;
myImage.Height = bi.PixelHeight;
myMosaique.Source =
CreateSmallImage(_vgaWidth / _scale, this.FileName);
myMosaique.Width = bi.PixelWidth;
myMosaique.Height = bi.PixelHeight;
myPlaceholder.Width = bi.PixelWidth;
myPlaceholder.Height = bi.PixelHeight;
}
public Rect ClipRect
{
get { return (Rect)GetValue(ClipRectProperty); }
set { SetValue(ClipRectProperty, value); }
}
public static DependencyProperty ClipRectProperty =
DependencyProperty.Register("ClipRect", typeof(Rect),
typeof(VgaImageUC), new FrameworkPropertyMetadata(
new PropertyChangedCallback(OnClipRectChanged)));
/// <summary>
/// プロパティ変更のコールバック
/// </summary>
private static void OnClipRectChanged(
DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
VgaImageUC control = (VgaImageUC)obj;
control.UpdateRect();
}
/// <summary>
/// モザイククリップ矩形の更新
/// </summary>
private void UpdateRect()
{
myMosaique.Clip = new RectangleGeometry(this.ClipRect);
myMosaique.Visibility = Visibility.Visible;
}
また、ファイル名を引数として受け取るコンストラクタも追加します。App.xaml.csから呼び出すときにこれを使います。
public VgaImageUC(string filename)
{
InitializeComponent();
this.FileName = filename;
}