Изучив ответ о вложенных наблюдаемых коллекциях один в другой , я стал намного понятнее, как реализовать это в моем случае. Сначала я переработал разметку XAML, заменив canvas
на listbox
:
<Window.Resources>
<DataTemplate x:Key="EllipseTemplate"
DataType="{x:Type local2:Figure_M}">
<ItemsControl ItemsSource="{Binding Path=Ellipses}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local3:Ellipse_M}">
<Ellipse Stroke="Black"
StrokeThickness="1"
Width="{Binding Width}"
Height="{Binding Height}"
Cursor="Hand" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
<DataTemplate x:Key="LineTemplate"
DataType="{x:Type local2:Figure_M}">
<ItemsControl ItemsSource="{Binding Path=Lines}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local3:Line_M}">
<Line Stroke="Black"
StrokeThickness="1"
X1="{Binding X1}"
X2="{Binding X2}"
Y1="{Binding Y1}"
Y2="{Binding Y2}"
Cursor="Hand" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
<DataTemplate x:Key="RectangleTemplate"
DataType="{x:Type local2:Figure_M}">
<ItemsControl ItemsSource="{Binding Path=Rectangles}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local3:Rectangle_M}">
<Rectangle Stroke="Black"
StrokeThickness="1"
Width="{Binding Width}"
Height="{Binding Height}"
Cursor="Hand" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Window.Resources>
<TabControl x:Name="Drawing_TabControl"
Grid.Row="0"
Background="WhiteSmoke"
SelectionChanged="Drawing_TabControl_SelectionChanged"
ItemsSource="{Binding Files}"
SelectedItem="{Binding SelectedFile_M}">
<TabControl.ItemTemplate>
<DataTemplate DataType="{x:Type local1:File_M}">
<StackPanel Orientation="Horizontal"
Background="Transparent">
<TextBlock Text="{Binding Path=Name_File}" Background="Transparent" />
<Button Height="18"
Width="18"
Background="Transparent"
BorderBrush="Transparent"
Click="Close_TabItem"
Visibility="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType=TabItem},
Converter={StaticResource B2V}}">
<Image Source="icons\close_x.png"/>
</Button>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type local1:File_M}">
<Grid Background="WhiteSmoke">
<Grid>
<Canvas x:Name="a"
Background="GhostWhite"
Height="6cm"
Width="16cm"
HorizontalAlignment="Center"
VerticalAlignment="Center">
</Canvas>
<Canvas x:Name="b"
Background="Transparent"
Height="6cm"
Width="16cm"
HorizontalAlignment="Center"
VerticalAlignment="Center"
SizeChanged="gridCanvas_SizeChanged"></Canvas>
<Border BorderBrush="Black"
BorderThickness="0.5 0.5 0.5 0.5"
Height="4cm"
Width="14cm"
HorizontalAlignment="Center"
VerticalAlignment="Center"></Border>
<Canvas x:Name="c"
Background="White"
Height="4cm"
Width="14cm"
HorizontalAlignment="Center"
VerticalAlignment="Center"></Canvas>
<Canvas x:Name="d"
Background="Transparent"
Height="4cm"
Width="14cm"
HorizontalAlignment="Center"
VerticalAlignment="Center"></Canvas>
</Grid>
<ListBox ItemsSource="{Binding Path=Figures}"
SelectedItem="{Binding Path=SelectedFigure_M}"
SelectionMode="Multiple"
Background="Transparent"
Height="4cm"
Width="14cm"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplateSelector>
<local:FigureTemplateSelector EllipseTemplate="{StaticResource EllipseTemplate}"
LineTemplate="{StaticResource LineTemplate}"
RectangleTemplate="{StaticResource RectangleTemplate}" />
</ListBox.ItemTemplateSelector>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Canvas.Left"
Value="{Binding X}" />
<Setter Property="Canvas.Top"
Value="{Binding Y}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border"
BorderThickness="1"
Padding="1">
<ContentPresenter Name="Content" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected"
Value="true">
<Setter TargetName="Border"
Property="BorderBrush"
Value="Blue" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
Затем я создал модель данных:
class Ellipse_M:
public class Ellipse_M : INotifyPropertyChanged
{
#region DataMembers
private double x = 0;
private double y = 0;
private double width = 0;
private double height = 0;
#endregion DataMembers
public double X
{
get
{
return x;
}
set
{
if (x == value)
{
return;
}
x = value;
OnPropertyChanged("X");
}
}
public double Y
{
get
{
return y;
}
set
{
if (y == value)
{
return;
}
y = value;
OnPropertyChanged("Y");
}
}
public double Width
{
get
{
return width;
}
set
{
if (width == value)
{
return;
}
width = value;
OnPropertyChanged("Width");
}
}
public double Height
{
get
{
return height;
}
set
{
if (height == value)
{
return;
}
height = value;
OnPropertyChanged("Height");
}
}
#region INotifyPropertyChanged Members
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
class Line_M:
public class Line_M : INotifyPropertyChanged
{
#region DataMembers
private double x1 = 0;
private double y1 = 0;
private double x2 = 0;
private double y2 = 0;
#endregion DataMembers
public double X1
{
get
{
return x1;
}
set
{
if (x1 == value)
{
return;
}
x1 = value;
OnPropertyChanged("X1");
}
}
public double Y1
{
get
{
return y1;
}
set
{
if (y1 == value)
{
return;
}
y1 = value;
OnPropertyChanged("Y1");
}
}
public double X2
{
get
{
return x2;
}
set
{
if (x2 == value)
{
return;
}
x2 = value;
OnPropertyChanged("X2");
}
}
public double Y2
{
get
{
return y2;
}
set
{
if (y2 == value)
{
return;
}
y2 = value;
OnPropertyChanged("Y1");
}
}
#region INotifyPropertyChanged Members
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
class Rectangle_M:
public class Rectangle_M : INotifyPropertyChanged
{
#region DataMembers
private double x = 0;
private double y = 0;
private double width = 0;
private double height = 0;
#endregion DataMembers
public double X
{
get
{
return x;
}
set
{
if (x == value)
{
return;
}
x = value;
OnPropertyChanged("X");
}
}
public double Y
{
get
{
return y;
}
set
{
if (y == value)
{
return;
}
y = value;
OnPropertyChanged("Y");
}
}
public double Width
{
get
{
return width;
}
set
{
if (width == value)
{
return;
}
width = value;
OnPropertyChanged("Width");
}
}
public double Height
{
get
{
return height;
}
set
{
if (height == value)
{
return;
}
height = value;
OnPropertyChanged("Height");
}
}
#region INotifyPropertyChanged Members
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
class Figure_M:
public class Figure_M : INotifyPropertyChanged
{
#region DataMembers(Ellipse_M, Line_M, Rectangle_M)
private double x = 0;
private double y = 0;
private Ellipse_M selectedEllipse_M;
private Line_M selectedLine_M;
private Rectangle_M selectedRectangle_M;
private string selectedFigure = "";
#endregion DataMembers(Ellipse_M, Line_M, Rectangle_M)
public Figure_M()
{
Ellipses = new ObservableCollection<Ellipse_M>();
Lines = new ObservableCollection<Line_M>();
Rectangles = new ObservableCollection<Rectangle_M>();
}
#region Property of Collections
public ObservableCollection<Ellipse_M> Ellipses { get; set; }
public ObservableCollection<Line_M> Lines { get; set; }
public ObservableCollection<Rectangle_M> Rectangles { get; set; }
#endregion Property of Collections
#region Property of DataMembers
public Ellipse_M SelectedEllipse_M
{
get { return selectedEllipse_M; }
set
{
if (value != selectedEllipse_M)
{
selectedEllipse_M = value;
OnPropertyChanged();
}
}
}
public Line_M SelectedLine_M
{
get { return selectedLine_M; }
set
{
if (value != selectedLine_M)
{
selectedLine_M = value;
OnPropertyChanged();
}
}
}
public Rectangle_M SelectedRectangle_M
{
get { return selectedRectangle_M; }
set
{
if (value != selectedRectangle_M)
{
selectedRectangle_M = value;
OnPropertyChanged();
}
}
}
public string SelectedFigure
{
get { return selectedFigure; }
set
{
selectedFigure = value;
}
}
public double X
{
get { return x; }
set
{
if (value != x)
{
x = value;
OnPropertyChanged();
}
}
}
public double Y
{
get { return y; }
set
{
if (value != y)
{
y = value;
OnPropertyChanged();
}
}
}
#endregion Property of DataMembers
#region INotifyPropertyChanged Members
/// <summary>
/// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
/// </summary>
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
class File_M:
public class File_M : INotifyPropertyChanged
{
#region DataMembers
private string name_File;
private Figure_M selectedFigure_M;
#endregion DataMembers
public string Name_File
{
get { return name_File; }
set
{
name_File = value;
OnPropertyChanged("Name_File");
}
}
public File_M()
{
Figures = new ObservableCollection<Figure_M>();
}
#region Property of Collections
public ObservableCollection<Figure_M> Figures { get; set; }
#endregion Property of Collections
#region Property of DataMembers
public Figure_M SelectedFigure_M
{
get { return selectedFigure_M; }
set
{
if (value != selectedFigure_M)
{
selectedFigure_M = value;
OnPropertyChanged();
}
}
}
#endregion Property of DataMembers
#region INotifyPropertyChanged Members
/// <summary>
/// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
/// </summary>
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
ViewModel :
public class ViewModel : INotifyPropertyChanged
{
#region DataMembers
private File_M selectedFile_M;
#endregion DataMembers
public ViewModel()
{
Files = new ObservableCollection<File_M>();
for(int i = 0; i < 3; i++)
{
File_M file_M = new File_M();
file_M.Name_File = $"Макет_{i + 1}";
for (int j = 3; j >= 0; j--)
{
Figure_M figure_M = new Figure_M();
Ellipse_M ellipse_M = new Ellipse_M();
ellipse_M.Height = 25 + j * 50;
ellipse_M.Width = 35 + j * 50;
figure_M.X = 70 + j*80;
figure_M.Y = 50;
figure_M.Ellipses.Add(ellipse_M);
file_M.Figures.Add(figure_M);
}
for (int j = 3; j >= 0; j--)
{
Figure_M figure_M = new Figure_M();
Line_M line_M = new Line_M();
line_M.X2 = 100 + j * 80;
line_M.Y2 = 100;
figure_M.X = 10 + j * 80;
figure_M.Y = 10;
figure_M.Lines.Add(line_M);
file_M.Figures.Add(figure_M);
}
for (int j = 3; j >= 0; j--)
{
Figure_M figure_M = new Figure_M();
Rectangle_M rectangle_M = new Rectangle_M();
rectangle_M.Height = 25 + j * 20;
rectangle_M.Width = 35 + j * 20;
figure_M.X = 70 + j * 80;
figure_M.Y = 50;
figure_M.Rectangles.Add(rectangle_M);
file_M.Figures.Add(figure_M);
}
Files.Add(file_M);
}
}
public ObservableCollection<File_M> Files { get; set; }
#region Property of DataMembers
public File_M SelectedFile_M
{
get { return selectedFile_M; }
set
{
if (value != selectedFile_M)
{
selectedFile_M = value;
OnPropertyChanged();
}
}
}
#endregion Property of DataMembers
#region INotifyPropertyChanged Members
/// <summary>
/// Raises the 'PropertyChanged' event when the value of a property of the view model has changed.
/// </summary>
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
Чтобы выбрать, какую фигуру разместить в данный момент, я создал FigureTemplateSelector:
public class FigureTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
DataTemplate template = null;
Figure_M figure_M = item as Figure_M;
if (figure_M.Ellipses.Count > 0)
{
template = EllipseTemplate;
if (template == null)
{
template = base.SelectTemplate(item, container);
}
}
else if(figure_M.Lines.Count > 0)
{
template = LineTemplate;
if (template == null)
{
template = base.SelectTemplate(item, container);
}
}
else if (figure_M.Rectangles.Count > 0)
{
template = RectangleTemplate;
if (template == null)
{
template = base.SelectTemplate(item, container);
}
}
else
{
template = base.SelectTemplate(item, container);
}
return template;
}
public DataTemplate EllipseTemplate { get; set; }
public DataTemplate LineTemplate { get; set; }
public DataTemplate RectangleTemplate { get; set; }
}
Другие холсты являются вспомогательными, поэтому я думаю, что мы должны сделайте то же самое и создайте коллекцию внутри класса Figure
.