Почему не обновляется ItemsControl?
Кто знаком с WPF (паттерн MVVM) можете ли мне подсказать как решить проблему с привязкой коллекции. Есть окно и в окне элементы , а в их Content атрибут привязаны мои страницы .xaml, в одной из страниц есть ItemsControl, к которому привязана коллекция, и при её обновлении, содержимое не меняется. Сразу скажу что всё я привязал правильно и что коллекция обновляется методом Add и является типом ObservableCollection, но дополню что моя страница отрисовывает коллекцию при инициализации конструктора ViewModel. Ниже прикрепил код
MainWindow.xaml (именно она открывается):
<Window x:Class="GraphMaster.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GraphMaster"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="150" Width="0.7*"/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Frame Grid.Row="1" Grid.RowSpan="6"
Content="{Binding EditPanelView}"/>
<TextBlock Grid.ColumnSpan="3"
DockPanel.Dock="Top"/>
<Border Grid.Row="1" Grid.Column="1"
Grid.RowSpan="6" Grid.ColumnSpan="2"
BorderBrush="LightGray" BorderThickness="1 1 0 0">
<Frame Content="{Binding GraphView}"/>
</Border>
</Grid>
</Window>
MainWindow.xaml.cs:
using GraphMaster.Views;
using System.Windows;
namespace GraphMaster
{
public partial class MainWindow : Window
{
public EditPanelView EditPanelView { get; set; }
public GraphView GraphView { get; set; }
public MainWindow(EditPanelView editPanelView, GraphView graphView)
{
InitializeComponent();
DataContext = this;
EditPanelView = editPanelView;
GraphView = graphView;
}
}
}
GraphView.xaml:
<Page x:Class="GraphMaster.Views.GraphView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GraphMaster.Views"
xmlns:shape="clr-namespace:GraphMaster.Models.Shapes"
xmlns:cnv="clr-namespace:GraphMaster.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="GraphView">
<Page.Resources>
<cnv:ConverterPointsCollection x:Key="ConverterPointsCollection"/>
</Page.Resources>
<ScrollViewer HorizontalScrollBarVisibility="Visible">
<ItemsControl ItemsSource="{Binding GraphFragments, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.Resources>
<HierarchicalDataTemplate DataType="{x:Type shape:CurveLine}" ItemsSource="{Binding Points}">
<Polyline Points="{Binding Points, Converter={StaticResource ConverterPointsCollection}}"
Stroke="{Binding Fill}"
StrokeThickness="{Binding Thickness}"/>
</HierarchicalDataTemplate>
</ItemsControl.Resources>
</ItemsControl>
</ScrollViewer>
</Page>
BaseViewModel.cs:
using GraphMaster.Models;
using GraphMaster.Services;
using System.ComponentModel;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace GraphMaster.ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
private protected ILoggerService logger;
private SmartDictionary repository { get; set; } = new SmartDictionary();
public SmartDictionary Repository
{
get => repository;
}
public BaseViewModel(ILoggerService logger)
{
StackTrace stackTrace = new StackTrace();
MethodBase? callingMethod = stackTrace.GetFrame(1)?.GetMethod();
this.logger = logger;
if(callingMethod?.DeclaringType != null) this.logger.Owner = callingMethod.DeclaringType;
}
public event PropertyChangedEventHandler? PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string prop = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}
}
}
GraphViewModel.cs
using GraphMaster.Models;
using GraphMaster.Models.Shapes;
using GraphMaster.Services;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
namespace GraphMaster.ViewModels
{
public class GraphViewModel : BaseViewModel
{
private ObservableCollection<Shape> graphFragments = new ObservableCollection<Shape>();
public ObservableCollection<Shape> GraphFragments
{
get => graphFragments;
set
{
graphFragments = value;
OnPropertyChanged(nameof(GraphFragments));
}
}
private int canvasWidth;
public int CanvasWidth
{
get => canvasWidth;
set
{
canvasWidth = value;
OnPropertyChanged(nameof(CanvasWidth));
}
}
private int canvasHeight;
public int CanvasHeight
{
get => canvasHeight;
set
{
canvasHeight = value;
OnPropertyChanged(nameof(CanvasHeight));
}
}
public GraphViewModel(ILoggerService logger) : base(logger)
{
Repository.CollectionChanged += OnCollectionChanged;
}
public void UpdateGraph()
{
object? graph = ((GraphFactory?)Repository["GraphFactory"])?.Build();
if (graph != null)
{
CurveLine result = (CurveLine)((IDrawable)graph).Draw();
CanvasWidth = result.Width + 50;
CanvasHeight = result.Height + 50;
Application.Current.Dispatcher.Invoke(() => {
GraphFragments.Add(result);
});
logger.Info($"Count: {GraphFragments.Count}");
}
}
private void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (Repository.Contains("GraphFactory"))
Application.Current.Dispatcher.Invoke(() => UpdateGraph());
}
}
}
Прикреплять GraphView.xaml.cs и EditPanelView.xaml.cs я не буду, так как там просто привязываются ViewModel этих вьюшек с помощью внедрения зависимостей