У меня есть проект WPF, который рисует несколько вещей в панели. Для следующего выпуска мне нужно добавить еще один тип вещей, чтобы рисовать в дополнение к существующим вещам. В настоящее время у меня есть сетка, которая содержит элемент ItemsControl, который содержит ItemsPanel и ItemSource. Существующий элемент ItemsSource выглядит примерно так:в WPF Мне нужно иметь коллекцию коллекции объектов рисования
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=DottedLines,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=BarrierLines,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=ProjectedLines,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=ProjectedCranes,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=CraneConfigs,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=Sightlines,
Mode=OneWay}"/>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=CraneCenters,
Mode=OneWay}"/>
</CompositeCollection>
</ItemsControl.ItemsSource>
Большинство коллекций представляют собой Линии или Многоугольники. У меня есть DataTemplates, определенные для привязки свойств объектов чертежа к вспомогательному объекту. Пример для объекта BarrierLine выглядит так:
<DataTemplate DataType="{x:Type c:BarrierLineArt}">
<Line
X1="{Binding Path=AX}"
Y1="{Binding Path=AY}"
X2="{Binding Path=BX}"
Y2="{Binding Path=BY}"
Stroke="{Binding Path=LineColor}"
StrokeThickness="{Binding Path=ScaledWeight}"
StrokeEndLineCap="Round"
StrokeStartLineCap="Round">
</Line>
</DataTemplate>
Это все работает хорошо. Теперь мне нужно добавить коллекцию вещей для рисования в дополнение к существующим вещам. Эта новая вещь имеет набор строк и значение перевода и вращения. К сожалению, мне нужно собрать коллекцию этих новых вещей. Каждый экземпляр имеет собственный перевод, ротацию и сбор строк. По сути, теперь у меня есть коллекция коллекций строк. Есть ли способ вставить CollectionContainers? Должен ли я попытаться добавить коллекцию в DataTemplate? Я не понимаю, в каком направлении я должен идти.
EDIT:
Хорошо, я создал программу корректуры из концепции, что я надеюсь, что отвечает требованиям Питера. Я предоставлю код ниже. Она состоит из пяти файлов: LineArt.cs ObstacleArt.cs MainWindowResource.cs MainWindow.xaml.cs MainWindow.xaml
Объект LineArt представляет данные, необходимые, чтобы нарисовать одну линию. Объект ObstacleArt представляет собой набор строк и перевод и поворот для этих строк. Я хочу иметь возможность нарисовать коллекцию линий (без трансляции или вращения) плюс набор препятствий, каждый из которых имеет набор линий.
Я попытался использовать предложение Питера, чтобы поместить CompositeCollection внутри свойства Collection CollectionContainer, который находится внутри CompositeCollection. Вы можете увидеть его в файле xaml внизу.
В свойстве Path коллекции, когда я помещаю «Препятствия [0] .Lines», он нарисует линии для первого препятствия. Но когда я вынимаю индекс и говорю «Obstacles.Lines», он не будет рисуй что угодно. Мне нужна способность рисовать все линии всех препятствий.
В дополнение к этому мне нужно будет установить перевод и поворот для каждого набора строк.
Вот файлы, вы должны быть способны их скомпилировать и запустить.
LineArt.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace POC_WPF_nestedDrawingObjects
{
public class LineArt : INotifyPropertyChanged
{
private Int32 _id = int.MinValue;
private double _ax = 0;
private double _ay = 0;
private double _bx = 0;
private double _by = 0;
private SolidColorBrush _lineColor = Brushes.Black;
private double _weight = 1;
private double _scaledWeight = 1;
public LineArt(
Int32 id,
double ax,
double ay,
double bx,
double by,
SolidColorBrush lineColor)
{
_id = id;
_ax = ax;
_ay = ay;
_bx = bx;
_by = by;
_lineColor = lineColor;
_weight = 1;
_scaledWeight = _weight;
}
public Int32 Id { get { return _id; } }
public double AX
{
get { return _ax; }
set
{
_ax = value;
SetPropertyChanged("AX");
}
}
public double AY
{
get { return _ay; }
set
{
_ay = value;
SetPropertyChanged("AY");
}
}
public double BX
{
get { return _bx; }
set
{
_bx = value;
SetPropertyChanged("BX");
}
}
public double BY
{
get { return _by; }
set
{
_by = value;
SetPropertyChanged("BY");
}
}
public SolidColorBrush LineColor
{
get { return _lineColor; }
set
{
_lineColor = value;
SetPropertyChanged("LineColor");
}
}
public double Weight
{
get { return _weight; }
set
{
_weight = value;
SetPropertyChanged("Weight");
}
}
public double ScaledWeight
{
get { return _scaledWeight; }
set
{
_scaledWeight = value;
SetPropertyChanged("ScaledWeight");
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void SetPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(
this,
new PropertyChangedEventArgs(prop));
}
}
#endregion INotifyPropertyChanged implementation
}
}
ObstacleArt.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace POC_WPF_nestedDrawingObjects
{
public class ObstacleArt : INotifyPropertyChanged
{
private Int32 _id = int.MinValue;
private ObservableCollection<LineArt> _lines
= new ObservableCollection<LineArt>();
private double _translateX = 0;
private double _translateY = 0;
private double _rotateAngle = 0;
public ObstacleArt(
Int32 id,
double translateX,
double translateY,
double rotateAngle)
{
_id = id;
_translateX = translateX;
_translateY = translateY;
_rotateAngle = rotateAngle;
}
public Int32 Id
{
get { return _id; }
}
public double TranslateX
{
get { return _translateX; }
set
{
_translateX = value;
SetPropertyChanged("TranslateX");
}
}
public double TranslateY
{
get { return _translateX; }
set
{
_translateX = value;
SetPropertyChanged("TranslateX");
}
}
public double RotateAngle
{
get { return _rotateAngle; }
set
{
_rotateAngle = value;
SetPropertyChanged("RotateAngle");
}
}
public ObservableCollection<LineArt> Lines
{
get { return _lines; }
}
public void NotifyLinesChanged()
{
SetPropertyChanged("Lines");
}
public void LinesAddPropertyChangedHandlers()
{
foreach (LineArt line in _lines)
{
line.PropertyChanged += line_PropertyChanged;
}
}
private void line_PropertyChanged(
object sender,
PropertyChangedEventArgs e)
{
SetPropertyChanged(e.PropertyName);
}
public void LinesDelPropertyChangedHandlers()
{
foreach (LineArt line in _lines)
{
line.PropertyChanged -= line_PropertyChanged;
}
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void SetPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(
this,
new PropertyChangedEventArgs(prop));
}
}
#endregion INotifyPropertyChanged implementation
}
}
MainWindowResource.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace POC_WPF_nestedDrawingObjects
{
public class MainWindowResource : INotifyPropertyChanged
{
private ObservableCollection<LineArt> _lines
= new ObservableCollection<LineArt>();
private ObservableCollection<ObstacleArt> _obstacles
= new ObservableCollection<ObstacleArt>();
public ObservableCollection<LineArt> Lines
{
get
{
return _lines;
}
}
public ObservableCollection<ObstacleArt> Obstacles
{
get
{
return _obstacles;
}
}
public void NotifyLinesChanged()
{
SetPropertyChanged("Lines");
}
public void NotifyObstaclesChanged()
{
SetPropertyChanged("Obstacles");
}
public void LinesAddPropertyChangedHandlers()
{
foreach (LineArt line in _lines)
{
line.PropertyChanged += line_PropertyChanged;
}
}
public void LinesDelPropertyChangedHandlers()
{
foreach (LineArt line in _lines)
{
line.PropertyChanged -= line_PropertyChanged;
}
}
private void line_PropertyChanged(
object sender,
PropertyChangedEventArgs e)
{
SetPropertyChanged(e.PropertyName);
}
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void SetPropertyChanged(string prop)
{
if (PropertyChanged != null)
{
PropertyChanged(
this,
new PropertyChangedEventArgs(prop));
}
}
#endregion INotifyPropertyChanged implementation
}
}
MainWindow.xaml.CS
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace POC_WPF_nestedDrawingObjects
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private MainWindowResource _mainWindowResource = null;
private SolidColorBrush _brush
= new SolidColorBrush(Color.FromArgb(255, 0, 0, 0));
public MainWindow()
{
LineArt line = null;
ObstacleArt obstacle = null;
InitializeComponent();
Application app = Application.Current;
_mainWindowResource
= (MainWindowResource)this.Resources["MainWindowResource"];
// initialize four lines, they will form a rectangle
_mainWindowResource.LinesDelPropertyChangedHandlers();
line = new LineArt(1, 10, 10, 30, 10, _brush);
_mainWindowResource.Lines.Add(line);
line = new LineArt(2, 30, 10, 30, 20, _brush);
_mainWindowResource.Lines.Add(line);
line = new LineArt(2, 30, 20, 10, 20, _brush);
_mainWindowResource.Lines.Add(line);
line = new LineArt(2, 10, 20, 10, 10, _brush);
_mainWindowResource.Lines.Add(line);
_mainWindowResource.LinesAddPropertyChangedHandlers();
_mainWindowResource.NotifyLinesChanged();
// initialize an obstacle made of four lines.
// the lines form a 20x20 square around 0,0.
// the obstacle should be trastlated to 50,50
// and not rotated
obstacle = new ObstacleArt(1, 50, 50, 0);
obstacle.LinesDelPropertyChangedHandlers();
line = new LineArt(1, -10, 10, 10, 10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(2, 10, 10, 10, -10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(3, 10, -10, -10, -10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(4, -10, -10, -10, 10, _brush);
obstacle.Lines.Add(line);
obstacle.LinesAddPropertyChangedHandlers();
_mainWindowResource.Obstacles.Add(obstacle);
// initialize an obstacle made of four lines.
// the lines form a 20x20 square around 0,0.
// the obstacle should be trastlated to 100,100
// and rotated to a 45 degree angle
obstacle = new ObstacleArt(1, 100, 100, 45);
obstacle.LinesDelPropertyChangedHandlers();
line = new LineArt(1, -10, 10, 10, 10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(2, 10, 10, 10, -10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(3, 10, -10, -10, -10, _brush);
obstacle.Lines.Add(line);
line = new LineArt(4, -10, -10, -10, 10, _brush);
obstacle.Lines.Add(line);
obstacle.LinesAddPropertyChangedHandlers();
_mainWindowResource.Obstacles.Add(obstacle);
_mainWindowResource.NotifyObstaclesChanged();
_mainWindowResource.NotifyLinesChanged();
foreach(ObstacleArt obstacleArt in _mainWindowResource.Obstacles)
{
obstacleArt.NotifyLinesChanged();
}
}
}
}
MainWindow.xaml
<Window x:Class="POC_WPF_nestedDrawingObjects.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:POC_WPF_nestedDrawingObjects"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<c:MainWindowResource x:Key="MainWindowResource"/>
<DataTemplate DataType="{x:Type c:LineArt}">
<Line
X1="{Binding Path=AX}"
Y1="{Binding Path=AY}"
X2="{Binding Path=BX}"
Y2="{Binding Path=BY}"
Stroke="{Binding Path=LineColor}"
StrokeThickness="{Binding Path=ScaledWeight}"
StrokeEndLineCap="Round"
StrokeStartLineCap="Round">
</Line>
</DataTemplate>
<Style x:Key="ContentCanvasStyle" TargetType="Canvas">
<Setter Property="RenderTransformOrigin" Value="0,0"/>
</Style>
</Window.Resources>
<Grid>
<ItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas x:Name="ContentCanvas"
Style="{StaticResource ContentCanvasStyle}">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsSource>
<CompositeCollection>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=Lines,
Mode=OneWay}"/>
<CollectionContainer>
<CollectionContainer.Collection>
<CompositeCollection>
<CollectionContainer
Collection="{Binding
Source={StaticResource MainWindowResource},
Path=Obstacles[0].Lines,
Mode=OneWay}"/>
</CompositeCollection>
</CollectionContainer.Collection>
</CollectionContainer>
</CompositeCollection>
</ItemsControl.ItemsSource>
</ItemsControl>
</Grid>
</Window>
Да, есть способ вложить коллекции. Это называется 'CompositeCollection', и вы используете это прямо здесь. «CompositeCollection» на самом деле представляет собой коллекцию и может быть коллекцией, используемой в «CollectionContainer». Из вашего вопроса неясно, пробовали ли вы это и/или что такое ваша _специфическая проблема. Это поможет, если вы предоставите [хороший, _minimal_, _complete_ пример кода] (https://stackoverflow.com/help/mcve), который четко показывает, что вы пробовали, а также подробное объяснение того, что делает код и как это отличается от того, что вы хотите. –
Питер, Спасибо за ответ. Я думал, что я представил то, о чем вы просите. Пример, который я предоставил из того, что я пробовал, является минимальным и полным. Я также представил подробное объяснение того, что делает код и как это отличается от того, что я хочу. Как вы можете видеть в коде, который я предоставил, я уже пользуюсь CompositeCollection. Проблема в том, что мне нужно иметь коллекцию объектов, которые имеют дополнительный уровень коллекции. Другими словами, мне нужно поставить CollectionContainer внутри существующего CollectionContainer. Это невозможно, так как подойти к этому? – dtaylor
К сожалению, приведенный вами пример не является ни минимальным, ни полным. Если бы он был минимальным, он показывал бы только одну вложенную коллекцию; ваш пример показывает не менее _seven_ коллекций в составной коллекции. Если бы это было полно, можно было бы скопировать/вставить код в пустой проект VS, скомпилировать его и увидеть, как он запускается. Ни то, ни другое не верны.Прочтите приведенную мной ссылку для получения подробной информации о том, какой пример кода действительно подходит. –