【问题标题】:ObservableCollection<Line> Not updating on the UIObservableCollection<Line> 未在 UI 上更新
【发布时间】:2016-06-10 17:45:22
【问题描述】:

我有一个 line 类型的 observablecollection(observable collections 自动实现 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>

【问题讨论】:

  • 你如何'连接到一个命令'?如果您已验证调用了 AddLine,我猜您将命令绑定到视图模型的不同实例。
  • @CharlesMager 如果您可以看一下,我添加了该命令的代码。我确实创建了一个新实例,但我将它设置为原始实例。这是否只是创建副本而不是参考?
  • 那段代码很好,我的意思是它是如何绑定到 UI 上的。您的 XAML 没有带有命令绑定的按钮或类似内容。
  • @CharlesMager 啊,我明白了。抱歉,我现在把它包括在内了。
  • 对我来说一切都很好。我唯一想知道的是您的财产名称:Lines。我怕它会和别的东西发生冲突。我将它重命名为 MyLines 只是为了暂时进行调试,以确保安全并确保我看到了正确的“线条”。

标签: c# wpf line observablecollection inotifypropertychanged


【解决方案1】:

问题是实例问题。您的Window 创建一个MapViewModel 的新实例,您的UserControl 创建一个MapViewModel 的新实例。

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

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

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

UserControlItemsControl 中删除资源和绑定的创建只会从其父级继承DataContext

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

【讨论】:

  • 太棒了!那解决了它。我以后需要对我的实例更加小心,感谢您以如此易于理解的方式对其进行解释。
猜你喜欢
  • 2014-01-01
  • 1970-01-01
  • 2012-01-15
  • 2017-12-28
  • 2016-11-05
  • 1970-01-01
  • 1970-01-01
  • 2019-03-16
  • 1970-01-01
相关资源
最近更新 更多