2016-08-22 3 views
0

Ich versuche, ein WPF-Canvas-Steuerelement zu erstellen, das Formen, Kurven und Textblöcke zeichnen, auswählen und löschen kann. Daher kann MVVM eine Liste von Ansichtsmodellen mit Canvas Children binden.Kann WPF Canvas Childs ObservableCollection binden ViewModel für verschiedene Formen und TextBlocks?

Canvas Kinder können jedoch nicht direkt gebunden werden. Also bin ich irgendwie festgefahren. Hätte sich im Internet umgeschaut, aber keine direkten Antworten gefunden. Ich habe jemanden gefunden, der den folgenden Weg vorschlägt, um Canvas Children zu binden, aber ich konnte nicht verstehen, welche Art von ViewModels "Nodes" sind und wie man verschiedene Formen, Kurven und TextBlocks in Knoten konvertiert.

Jede Hilfe wird geschätzt. Danke im Voraus.

<ItemsControl ItemsSource="{Binding Path=Nodes}"> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <Canvas /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemContainerStyle> 
     <Style TargetType="ContentPresenter"> 
      <Setter Property="Canvas.Left" Value="{Binding Path=XPos}" /> 
      <Setter Property="Canvas.Top" Value="{Binding Path=YPos}" /> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
</ItemsControl> 
+0

Diese Frage ist fast ein bisschen zu breit. Die ViewModels könnten fast alles sein, abhängig davon, was Sie anzeigen möchten. Die einzige Garantie ist, dass sie 2 Props 'XPos' und' YPos' haben. – lokusking

Antwort

1

Ihre Ansicht Modell eine Basisklasse enthalten sollte, die die NodeXPos und YPos Eigenschaften und abgeleiteten Klassen für die speziellen Knotentypen definiert, z.B. TextNode und ShapeNode:

public class Node 
{ 
    public double XPos { get; set; } 
    public double YPos { get; set; } 
} 

public class TextNode : Node 
{ 
    public string Text { get; set; } 
} 

public class ShapeNode : Node 
{ 
    public Geometry Geometry { get; set; } 
    public Brush Stroke { get; set; } 
    public Brush Fill { get; set; } 
} 

public class ViewModel 
{ 
    public ObservableCollection<Node> Nodes { get; } = new ObservableCollection<Node>(); 
} 

In XAML, würden Sie Datatemplates für die spezifischen Knoten Typen hinzufügen, wie unten gezeigt. Einzelheiten finden Sie im Artikel Data Templating Overview auf MSDN.

<ItemsControl ItemsSource="{Binding Path=Nodes}"> 
    <ItemsControl.Resources> 
     <DataTemplate DataType="{x:Type local:TextNode}"> 
      <TextBlock Text="{Binding Text}"/> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type local:ShapeNode}"> 
      <Path Data="{Binding Geometry}" Stroke="{Binding Stroke}" Fill="{Binding Fill}"/> 
     </DataTemplate> 
    </ItemsControl.Resources> 
    <ItemsControl.ItemsPanel> 
     <ItemsPanelTemplate> 
      <Canvas /> 
     </ItemsPanelTemplate> 
    </ItemsControl.ItemsPanel> 
    <ItemsControl.ItemContainerStyle> 
     <Style TargetType="ContentPresenter"> 
      <Setter Property="Canvas.Left" Value="{Binding Path=XPos}" /> 
      <Setter Property="Canvas.Top" Value="{Binding Path=YPos}" /> 
     </Style> 
    </ItemsControl.ItemContainerStyle> 
</ItemsControl> 

Sie können nun verschiedene Knoten auf eine Instanz der Hauptansicht Modellklasse hinzufügen und legen Sie die Datacontext-Fenster auf diese Instanz:

public MainWindow() 
{ 
    InitializeComponent(); 

    var vm = new ViewModel(); 

    vm.Nodes.Add(new TextNode 
    { 
     XPos = 50, 
     YPos = 100, 
     Text = "Hello, World." 
    }); 

    vm.Nodes.Add(new ShapeNode 
    { 
     XPos = 100, 
     YPos = 200, 
     Geometry = new EllipseGeometry { RadiusX = 50, RadiusY = 50 }, 
     Fill = Brushes.Red 
    }); 

    DataContext = vm; 
} 

Wenn Sie die Ansicht auf Eigenschaft reagieren wollen Änderungen der Knoten sollte die Node-Klasse die INotifyPropertyChanged-Schnittstelle implementieren.

Wenn die Elemente auswählbar sein sollen, sollten Sie ItemsControl durch eine ListBox ersetzen. Der TargetType des ItemContainerStyle wäre dann ListBoxItem, und Sie würden seine IsSelected-Eigenschaft an eine entsprechende Eigenschaft in Ihrer Node-Klasse binden.

+0

Vielen Dank für die ausführliche Antwort. Funktioniert wunderbar. :) –

Verwandte Themen