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
绑定到的实例。
最简单的更改方法可能是将 MapView
的 DataContext
设置为 Window
中的 MapViewModel
:
<local:MapView DataContext="{StaticResource MapVM}" />
并从您的 UserControl
中删除资源和绑定的创建,ItemsControl
将仅继承其父项的 DataContext
。
<Grid x:Name="LayoutRoot">
<ItemsControl x:Name="Items" ItemsSource="{Binding Lines}">
...
我有一个类型为 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
绑定到的实例。
最简单的更改方法可能是将 MapView
的 DataContext
设置为 Window
中的 MapViewModel
:
<local:MapView DataContext="{StaticResource MapVM}" />
并从您的 UserControl
中删除资源和绑定的创建,ItemsControl
将仅继承其父项的 DataContext
。
<Grid x:Name="LayoutRoot">
<ItemsControl x:Name="Items" ItemsSource="{Binding Lines}">
...