ObservableCollection<Line> 未在 UI 上更新

ObservableCollection<Line> Not updating on the UI

我有一个类型为 line 的 observablecollection(可观察集合自动实现 INotifyPropertyChanged 接口)和一个向其添加一行的函数,称为 CreateLine。如果我在构造函数中调用 CreateLine,它就会出现。但是,如果我尝试在之后(通过连接到命令)执行此操作,它将不会更新 UI。有什么想法吗?

代码:

namespace MovementMap.ViewModels
{
    class MapViewModel : INotifyPropertyChanged
    {
        public AddLineCommand addlinecommand { get; set; }

        public MapViewModel()
        {
            //test
            CreateLine(100, 100, 150, 150);
            CreateLine(150, 150, 200, 280);

            addlinecommand = new AddLineCommand(this);
        }
        private ObservableCollection<Line> lines = new ObservableCollection<Line>();
        public ObservableCollection<Line> Lines
        {
            get
            {
                return lines;
            }
        }
        public void CreateLine(int x1, int y1, int x2, int y2)
        {
            Line line = new Line();
            line.X1 = x1;
            line.Y1 = y1;
            line.X2 = x2;
            line.Y2 = y2;

            line.StrokeThickness = 2;

            SolidColorBrush black = new SolidColorBrush();
            black.Color = Colors.Black;

            line.Stroke = black;

            Lines.Add(line);
            OnPropertyChanged("Lines");
        }
        public void AddLine()
        {
            //doesnt seem to be updating ui.
            CreateLine(0, 0, 100, 100);
        }
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }
}

XAML:

<UserControl x:Class="MovementMap.MapView"
             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:viewmodel="clr-namespace:MovementMap.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <viewmodel:MapViewModel x:Key="MapVM"/>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" DataContext="{Binding Mode=OneWay, Source={StaticResource MapVM}}">
        <ItemsControl x:Name="Items" ItemsSource="{Binding Lines, Source={StaticResource MapVM}, UpdateSourceTrigger=PropertyChanged}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
        <!--<Line X1="0" X2="100" Y1="0" Y2="100" Stroke="Red" StrokeThickness="4"/>-->
    </Grid>
</UserControl>

命令:

namespace MovementMap.ViewModels.Commands
{
    class AddLineCommand : ICommand
    {
        private MapViewModel ViewModel;
        public AddLineCommand(MapViewModel VM)
        {
            ViewModel = VM;
        }


        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
        public void Execute(object parameter)
        {
            this.ViewModel.AddLine();
        }
    }
}

按钮XAML:

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MovementMap" x:Class="MovementMap.MainWindow"
        xmlns:viewmodel="clr-namespace:MovementMap.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <viewmodel:MapViewModel x:Key="MapVM"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="100"/>
        </Grid.ColumnDefinitions>
        <local:MapView/>
        <Button Grid.Column="1" Content="Add Line" Height="20" Command="{Binding addlinecommand, Source={StaticResource MapVM}}"/>
    </Grid>
</Window>

问题是实例的问题。您的 Window 创建了 MapViewModel 的新实例,您的 UserControl 创建了 MapViewModel.

的新实例

当您单击该按钮时,会在 Window 创建的实例上向 Lines 添加一行。这不是您的 UserControl 绑定到的实例。

最简单的更改方法可能是将 MapViewDataContext 设置为 Window 中的 MapViewModel:

<local:MapView DataContext="{StaticResource MapVM}" />

并从您的 UserControl 中删除资源和绑定的创建,ItemsControl 将仅继承其父项的 DataContext

<Grid x:Name="LayoutRoot">
    <ItemsControl x:Name="Items" ItemsSource="{Binding Lines}">
        ...