WPF / C#でカスタムMultiSelector / ItemsControlを作成する方法
-
22-07-2019 - |
質問
C#/ WPFで作図アプリケーションを作成しようとしています。クローンを作成しようとはしていませんが、Microsoft Visioに似ています。コーディングしているときにこの質問を書いて、誰かが役に立つと思う場合に備えて、私が抱えていたすべての問題を入れました。考えすぎていたのかもしれませんが、キーボードを使ってより良いコードを作成できると思うので、キャッチした詳細については自由に提案してください(文法は除く:-))
簡単に言うと
すべてのアイテムが(0,0)に配置されているのはなぜですか?
コード:
public class Diagram : MultiSelector
{
public Diagram()
{
this.CanSelectMultipleItems = true;
// The canvas supports absolute positioning
FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas));
this.ItemsPanel = new ItemsPanelTemplate(panel);
// Tells the container where to position the items
this.ItemContainerStyle = new Style();
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
FrameworkElement contentitem = element as FrameworkElement;
Binding leftBinding = new Binding("X");
Binding topBinding = new Binding("Y");
contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
contentitem.SetBinding(Canvas.TopProperty, topBinding);
base.PrepareContainerForItemOverride(element, item);
}
public class DiagramItem : ContentControl
{
private Point _location;
public DiagramItem()
{
}
static DiagramItem()
{
}
public Point Location
{
get { return _location; }
set
{
_location = value;
}
}
public double X
{
get { return _location.X; }
set
{
_location.X = value;
}
}
public double Y
{
get { return _location.Y; }
set
{
_location.Y = value;
}
}
}
//...
わかりました。そのため、 Diagram:ItemsControl は、アイテムパネルのアイテムDiagramItem.Locationで定義された位置にアイテムを配置します。 DiagramItemのXプロパティを変更すると、ダイアグラムはx軸上でアイテムを移動します。
注: MultiSelectorはItemsControlおよびSelectorから派生し、表示されたアイテムを選択可能にする必要があるため、ここでのみ使用されます。
可能であればxamlを使用しない方がよいことに注意してください。
長く:
ユーザーに表示されるダイアグラムインスタンスには、次の要件があります。
- 複数のDiagramItemがあります。
- ユーザーは複数のDiagramItemを選択できます。
- DiagramItemsは、ダイアグラム上の任意の場所でサイズ変更、回転、ドラッグできます。
- キーボードを使用してDiagramItems間を移動できます。
この質問に関連するクラスは基本的に2つ、おそらく3つあります。
- 図はSystem.Windows.Controls.Primitives。 MultiSelector を拡張します:Selector:ItemsControl
- DiagramItem は、 ContentControl またはその他のコントロールを拡張します
Diagram.ItemsPanel、つまりアイテムを表示する視覚パネルは、キャンバスのような絶対配置をサポートするパネルでなければなりません。
MultiSelectorから派生したクラスを実装する方法と、この質問に関連するリソースを指定できますか?
カスタムMultiSelector / ItemsControlを実装する際に考慮すべきことは何ですか?
リソース:
自分の問題に関連するリソースはほとんど見つかりませんでしたが、何を探しているのかわかりません。 Reflectorを使用してListBoxおよびListBoxItemのソースコードを読みましたが、あまり有用ではありませんでした。
その他のリソース:
解決
OK、明らかにこれはバインディングとプロパティフレームワークを使用して簡単に実現できます。
public class Diagram : MultiSelector
{
public Diagram()
{
this.CanSelectMultipleItems = true;
// The canvas supports absolute positioning
FrameworkElementFactory panel = new FrameworkElementFactory(typeof(Canvas));
this.ItemsPanel = new ItemsPanelTemplate(panel);
// Tells the container where to position the items
this.ItemContainerStyle = new Style();
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.LeftProperty, new Binding("X")));
this.ItemContainerStyle.Setters.Add(new Setter(Canvas.TopProperty, new Binding("Y")));
}
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
FrameworkElement contentitem = element as FrameworkElement;
Binding leftBinding = new Binding("XProperty");
leftBinding.Source = contentitem;
Binding topBinding = new Binding("YProperty");
topBinding.Source = contentitem;
contentitem.SetBinding(Canvas.LeftProperty, leftBinding);
contentitem.SetBinding(Canvas.TopProperty, topBinding);
base.PrepareContainerForItemOverride(element, item);
}
public class DiagramItem : ContentControl
{
public static readonly DependencyProperty XProperty;
public static readonly DependencyProperty YProperty;
public static readonly RoutedEvent SelectedEvent;
public static readonly RoutedEvent UnselectedEvent;
public static readonly DependencyProperty IsSelectedProperty;
public DiagramItem()
{
}
static DiagramItem()
{
XProperty = DependencyProperty.Register("XProperty", typeof(Double), typeof(DiagramItem));
YProperty = DependencyProperty.Register("YProperty", typeof(Double), typeof(DiagramItem));
SelectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
UnselectedEvent = MultiSelector.SelectedEvent.AddOwner(typeof(DiagramItem));
IsSelectedProperty = MultiSelector.IsSelectedProperty.AddOwner(typeof(DiagramItem));
}
public Double X
{
get
{
return (Double)this.GetValue(XProperty);
}
set
{
this.SetValue(XProperty, value);
}
}
public Double Y
{
get
{
return (Double)this.GetValue(YProperty);
}
set
{
this.SetValue(YProperty, value);
}
}
public Point Location
{
get
{
return new Point(X, Y);
}
set
{
this.X = value.X;
this.Y = value.Y;
}
}
}
魔法はBingingsの適切な使用にあり、キーはcontentitemをSourceとして追加することでした。次のステップは明らかにアイテムの選択を処理することですが、それは別の質問です。
他のヒント
ヘルプの場合は、NetworkViewと呼ばれるカスタムコントロールのグラフとダイアグラムに基づいてコードプロジェクトの記事を書きました。
http:// www。 codeproject.com/Articles/182683/NetworkView-A-WPF-custom-control-for-visualizing-a