Как правильно привязать ObservableCollection внутри ObservableCollection к ItemsControl (WPF)C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Гость
 Как правильно привязать ObservableCollection внутри ObservableCollection к ItemsControl (WPF)

Сообщение Гость »


Прежде чем я начну с объяснения проблемы, я новичок в WPF и еще не уловил всех концепций шаблона MVVM.

У меня есть ObservableCollection, где Vertex — это класс, представляющий вершину в графе. Он содержит свойства, представляющие его положение: X,Y и Point Position. Он также содержит ObservableCollection, где Edge — это простая модель, содержащая 2 вершины (от и до) и ее вес в виде целого числа.

Мое намерение состоит в том, чтобы отобразить как совокупность вершин (в виде эллипсов), так и ребра в виде линий. Представление, которое я пытаюсь создать, должно позволять добавлять эти вершины и ребра, что я и делаю с помощью команд, поскольку пытаюсь следовать архитектуре MVVM.

Вершины можно добавлять без проблем, однако проблемы начинаются, когда я пытаюсь добавить ребро из одной вершины в другую. Первая выбранная вершина ребра перемещается в совершенно другое место на виде (+ по осям x и y), а линия, представляющая ребро, имеет правильный наклон, но также перемещается в другое место.

Вот краткая демонстрация того, что я имею в виду: Ситуация перед добавлением ребра Ситуация после добавления ребра

Вот что у меня сейчас есть в файле xaml для представления с холстом (только важная часть с ItemsControl):

И вот что у меня есть в файле ViewModel:

публичный класс SceneEditorViewModel: BaseViewModel { режим частного перечисления { Режим добавления вершин, EdgeAdditionMode, Режим просмотра, Режим удаления вершин } частный только для чтения SceneEntry _sceneEntry; частный режим _mode = Mode.ViewMode; частный Вертекс? _firstClickedVertex; общедоступный график IGraph => _sceneEntry.Graph; /// /// Команды для кнопок /// общественный ICommand LoadFileCommand {получить; } общественный ICommand SetNameCommand {получить; } общественный ICommand BackCommand {получить; } общественный ICommand AddVertexCommand {get; } общественный ICommand AddEdgeCommand {получить; } общественный ICommand ClearCommand {получить; } общественный ICommand DeleteVertexCommand {get; } /// /// Команда вызывается после щелчка пользователя по области холста /// общественный ICommand CanvasClickCommand {получить; } общедоступная строка NameTextBox { получить => _sceneEntry.Name; набор { _sceneEntry.Name = значение; ПриИзмененииСвойства(); } } public SceneEditorViewModel (NavigationManager NavigationManager, SceneEntry? запись = null) { LoadFileCommand = новый RelayCommand (LoadFile, o => true); SetNameCommand = новая RelayCommand (SetName, o => true); BackCommand = new NavigationCommand(новый NavigationService(navigationManager, () => новая SceneMenuViewModel(navigationManager))); ДобавитьВертексКоманда = новая команда реле( o => _mode = _mode == Mode.VertexAdditionMode ? Mode.ViewMode : Mode.VertexAdditionMode, о => правда); AddEdgeCommand = новая команда реле( o => _mode = _mode == Mode.EdgeAdditionMode ? Mode.ViewMode : Mode.EdgeAdditionMode, о => правда); CanvasClickCommand = новый EventRelayCommand(OnMouseDown, o => true); DeleteVertexCommand = новый RelayCommand (DeleteVertex, o => true); _sceneEntry = запись ?? новый SceneEntry("", SceneMenuViewModel.SceneIdCounter++, новый Graph()); ClearCommand = new RelayCommand(o => _sceneEntry.Graph.Vertices.Clear(), o => true); если (запись равна нулю) { App.Scenes.Add(new SceneEntryViewModel(navigationManager, _sceneEntry)); } } частная пустота LoadFile (объект obj) { var openFileDialog = новый OpenFileDialog { Filter = "Файлы графиков (*.graph)|*.graph" }; если (openFileDialog.ShowDialog() == true) { вар файл = openFileDialog.FileName; вар сериализатор = новый GraphSerializer(); вар график = сериализатор.Десериализовать(файл); _sceneEntry.Graph = график; } //var сериализатор = новый сериализатор(); //var Graph = сериализатор.Deserialize(OpenFileDialog.FileName); //_graphViewModel.Graph = график; } частная пустота SetName (объект obj) { если (NameTextBox != "") { _sceneEntry.Name = NameTextBox; } } частная пустота DeleteVertex (объект obj) { _mode = _mode == Mode.VertexDeletionMode ? Mode.ViewMode : Mode.VertexDeletionMode; } частная пустота OnMouseDown (MouseButtonEventArgs e) { вар отправитель = e.Source как IInputElement; вар позиция = e.GetPosition(отправитель); переключатель (_mode) { Case Mode.VertexAdditionMode: var vertex = new Vertex("", Position.X, Position.Y, new ObservableCollection()); _sceneEntry.Graph.AddVertex(вершина); перерыв; Case Mode.EdgeAdditionMode: var first = _sceneEntry.Graph.Vertices.FirstOrDefault(v => v.X - 10 < позиция.X && позиция.X < v.X + 10 && v.Y - 10 < позиция.Y && позиция.Y < v.Y + 10); если (первое значение равно нулю) перерыв; если (_firstClickedVertex имеет значение null ) { first.IsSelected = true; _firstClickedVertex = первый; } еще { если (первый != _firstClickedVertex) { вар край = новый край() { FromVertex = новая вершина (_firstClickedVertex), ToVertex = новая вершина (первая), IsDirected = ложь, Вес = 1 }; _sceneEntry.Graph.Vertices.First(v => v == _firstClickedVertex).Edges.Add(edge); } _firstClickedVertex.IsSelected = ложь; _firstClickedVertex = ноль; } перерыв; Case Mode.VertexDeletionMode: var selected = _sceneEntry.Graph.Vertices.FirstOrDefault(v => v.X - 10 < позиция.X && позиция.X < v.X + 10 && v.Y - 10 < позиция.Y && позиция.Y < в.Й+10); если (выбрано значение null) перерыв; _sceneEntry.Graph.Vertices.Remove(выделено); перерыв; по умолчанию: перерыв; } } } Код действительно беспорядочный (в основном из-за попыток выяснить, в чем именно заключается проблема), но намерение должно быть несколько видно.

Класс Graph — это, по сути, просто класс, инкапсулирующий ObservableCollection, и все модели реализуют интерфейс INotifyPropertyChaned.

На правильном ли я пути, используя этот подход внутри файла xaml, или есть гораздо лучший способ сделать то, что я хочу?
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»