Adorner を使ってコントロールでコントロールを修飾する
# 「 WPF で色々やってみている」こと第一弾w
WPF では Adorner コントロールを使って、既存のコントロールを修飾する事が出来ます。
public class SampleAdorner : Adorner { public SampleAdorner(UIElement adornedElement) : base(adornedElement) { } protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); drawingContext.DrawEllipse(Brushes.Aqua, new Pen(), new Point(80, 80), 100, 100); } }
利用する側のコードはこんな感じ。
// 修飾する対象のコントロールのレイヤーを取得 var layer = AdornerLayer.GetAdornerLayer(Button1); // Adorner のインスタンスを生成 var adorner = new SampleAdorner(Button1); // レイヤーに Adorner を追加 layer.Add(adorner);
……で、この機能のサンプルを調べても、↑の様に Draw 系のサンプルしか出てこないんですよね。
でも、うまく利用すればコントロールも追加出来るらしいので、頑張って実装してみました。
ControlAdorner.cs
public class ControlAdorner : Adorner { // レイヤー上の実体は Canvas private Canvas _adornerCanvas; // Adorner の VisualChild は空っぽなので、固定で 1 を返す様にする protected override int VisualChildrenCount { get { return 1; } } public ControlAdorner(UIElement adornedElement) : base(adornedElement) { _adornerCanvas = new Canvas() { Background = Brushes.Transparent }; } public void AddAdornment(UIElement child) { // Canvas にコントロールを追加 _adornerCanvas.Children.Add(child); } protected override Size ArrangeOverride(Size finalSize) { // Canvas を Adorner のサイズにリサイズ _adornerCanvas.Arrange(new Rect(finalSize)); Canvas.SetTop(_adornerCanvas, 0); Canvas.SetLeft(_adornerCanvas, 0); return finalSize; } protected override Visual GetVisualChild(int index) { if (VisualChildrenCount <= index) { throw new IndexOutOfRangeException(); } // 常に Canvas を返す return _adornerCanvas; } }
使う側 (Window.xaml.cs)
var layer = AdornerLayer.GetAdornerLayer(TextBox1); var adorner = new ControlAdorner(TextBox1); // イメージを追加してみる var image = new Image() { Stretch = Stretch.Fill, Source = new BitmapImage(new Uri(@"C:\sample.jpg")), Opacity = 0.25f }; // イメージのレイヤー上の表示位置を指定 Canvas.SetTop(image, 15); Canvas.SetLeft(image, 20); // Adorner にイメージを追加 adorner.AddAdornment(image); // レイヤーに Adorner を追加 layer.Add(adorner);
……使う側は、どこかのコードとそっくりですw
# まぁ、元々 Visual Studio 2010 の Editor Viewport Adorner と同じ様な事をしたいと云うのが発端だったのでww
# ちなみに、 VS2010 のテキストエディタは、更にテキスト表示部分自体をレイヤー化して、テキストの後ろ側にも独自のレイヤーを追加出来る様にしている様ですが。
# ※なお、↑に書いたコードで追加されたレイヤーは、常に元のコントロールの上に表示されます。(なので、このままだと背景イメージの挿入とかには使えない)
※投稿している環境の制限で画像が貼れないため、スクリーンショットは後で追加予定。。。