PhotoShopの機能を模倣していくこと
入門者にはあまりに壮大な目標に感じますが、まあどこまでやるかによりますね。
PhotoShopは持っていませんが、ツールバーにある[TEXT]ボタンを選択して画面をクリックするとそこに枠が出る(ドラッグで範囲指定?)みたいなやつですね?
フォントや色を変更できて、欲を言えばマウスで移動やリサイズができる。と
凝ったUIの作りこみはロジック以上に難しいことが多いです(私はあまり手を出さないようにしています^^;
とはいえ出発点としてミニマムかつ、そこそこ遊べるような参考コードを書いてみました。
[仕様]
画像エリアをダブルクリックでその場所にTextBox
を生成
TextBox
の右クリックメニューに削除(コピー等はTextBox
のコピーではなく、テキストのコピー)
テキストの編集はその場で可能(複数行に対応)
ほかのプロパティはPropertyGrid
で編集(クリックしたTextBox
をPropertyGrid
に割り当てるため、選択が少し重いです)
- 移動は
CanvasLeft
・CanvasTop
- サイズは
Width
・Height
(NaN
で自動調整)
- フォントはFontなんちゃら
- 色は
Foreground
NuGetからExtended.Wpf.Toolkit
をインストールしてください(PropertyGrid
だけ使います)
xml
1<Window
2 x:Class="Questions233943.MainWindow"
3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5 xmlns:local="clr-namespace:Questions233943"
6 xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
7 Width="800"
8 Height="450">
9 <Window.Resources>
10 <ContextMenu x:Key="TextBoxContextMenu">
11 <MenuItem Command="ApplicationCommands.Copy" />
12 <MenuItem Command="ApplicationCommands.Cut" />
13 <MenuItem Command="ApplicationCommands.Paste" />
14 <MenuItem Click="DelMenuItem_Click" Header="削除" />
15 </ContextMenu>
16
17 <Style x:Key="TextBoxStyle" TargetType="{x:Type local:TextBoxEx}">
18 <Setter Property="AcceptsReturn" Value="True" />
19 <Setter Property="AcceptsTab" Value="True" />
20 <Setter Property="Background" Value="{x:Null}" />
21 <Setter Property="BorderBrush" Value="{x:Null}" />
22 <Setter Property="ContextMenu" Value="{StaticResource TextBoxContextMenu}" />
23 <Setter Property="FontSize" Value="16px" />
24 <Setter Property="FontWeight" Value="bold" />
25 <Setter Property="Foreground" Value="Red" />
26 <Setter Property="Text" Value="テキスト" />
27 <Setter Property="TextWrapping" Value="Wrap" />
28 <Setter Property="Template">
29 <Setter.Value>
30 <ControlTemplate TargetType="{x:Type TextBox}">
31 <Border
32 x:Name="border"
33 Background="{TemplateBinding Background}"
34 BorderBrush="{TemplateBinding BorderBrush}"
35 BorderThickness="{TemplateBinding BorderThickness}"
36 SnapsToDevicePixels="True">
37 <ScrollViewer
38 x:Name="PART_ContentHost"
39 Focusable="false"
40 HorizontalScrollBarVisibility="Hidden"
41 VerticalScrollBarVisibility="Hidden" />
42 </Border>
43 <ControlTemplate.Triggers>
44 <Trigger Property="IsMouseOver" Value="true">
45 <Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
46 </Trigger>
47 <Trigger Property="IsFocused" Value="true">
48 <Setter TargetName="border" Property="BorderBrush" Value="#FF7EB4EA" />
49 </Trigger>
50 </ControlTemplate.Triggers>
51 </ControlTemplate>
52 </Setter.Value>
53 </Setter>
54 </Style>
55 </Window.Resources>
56 <Grid>
57 <Grid.ColumnDefinitions>
58 <ColumnDefinition Width="2*" />
59 <ColumnDefinition Width="5" />
60 <ColumnDefinition />
61 </Grid.ColumnDefinitions>
62 <Canvas x:Name="canvas" MouseLeftButtonDown="Canvas_MouseLeftButtonDown">
63 <Image Source="Resources\whippet.jpg" />
64 </Canvas>
65 <GridSplitter Grid.Column="1" HorizontalAlignment="Stretch" />
66 <xctk:PropertyGrid x:Name="propertyGrid" Grid.Column="2" />
67 </Grid>
68</Window>
cs
1using System.Windows;
2using System.Windows.Controls;
3using System.Windows.Input;
4
5namespace Questions233943
6{
7 // PropertyGridでいじれるようにCanvas.Left Canvas.Topをラップ
8 public class TextBoxEx : TextBox
9 {
10 public static readonly DependencyProperty CanvasLeftProperty
11 = DependencyProperty.Register(nameof(CanvasLeft), typeof(double), typeof(TextBoxEx),
12 new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnCanvasLeftChanged)));
13 public double CanvasLeft { get => (double)GetValue(CanvasLeftProperty); set => SetValue(CanvasLeftProperty, value); }
14 private static void OnCanvasLeftChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
15 {
16 if(obj is TextBoxEx ctrl) Canvas.SetLeft(ctrl, ctrl.CanvasLeft);
17 }
18
19 public static readonly DependencyProperty CanvasTopProperty
20 = DependencyProperty.Register(nameof(CanvasTop), typeof(double), typeof(TextBoxEx),
21 new FrameworkPropertyMetadata(0d, new PropertyChangedCallback(OnCanvasTopChanged)));
22 public double CanvasTop { get => (double)GetValue(CanvasTopProperty); set => SetValue(CanvasTopProperty, value); }
23 private static void OnCanvasTopChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
24 {
25 if(obj is TextBoxEx ctrl) Canvas.SetTop(ctrl, ctrl.CanvasTop);
26 }
27 }
28
29 public partial class MainWindow : Window
30 {
31 public MainWindow() => InitializeComponent();
32
33 private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
34 {
35 if(e.ClickCount == 2)
36 {
37 var textBox = new TextBoxEx
38 {
39 Style = FindResource("TextBoxStyle") as Style,
40 CanvasLeft = e.GetPosition(canvas).X,
41 CanvasTop = e.GetPosition(canvas).Y
42 };
43 textBox.GotFocus += TextBox_GotFocus;
44 canvas.Children.Add(textBox);
45 }
46 }
47
48 private void TextBox_GotFocus(object sender, RoutedEventArgs e)
49 => propertyGrid.SelectedObject = sender;
50
51 private void DelMenuItem_Click(object sender, RoutedEventArgs e)
52 {
53 if(sender is MenuItem menuItem)
54 {
55 if(menuItem.Parent is ContextMenu contextMenu)
56 {
57 if(contextMenu.PlacementTarget is TextBoxEx textBox)
58 {
59 propertyGrid.SelectedObject = null;
60 textBox.GotFocus -= TextBox_GotFocus;
61 canvas.Children.Remove(textBox);
62 }
63 }
64 }
65 }
66 }
67}
マウスでサイズ変更・移動をちゃんとやるなら、この辺を参考に頑張ってください。