我有一个带有绑定的列表视图,但它没有更新。有人能找到这个bug吗?希望我有一些钱,因为我会提供奖励。
在此屏幕上,当特定恐龙的状态发生变化时,右侧窗口(活动恐龙列表)不会更新(请注意,当您单击恐龙(在本例中为Nancy)时,它会正确显示她的状态是“移动食物”,而“活跃的恐龙名单”则显示她仍在休息:
以下是所有相关代码,从窗口的XAML开始:
<Window x:Class="DinosaurIsland.ActiveDinosaurList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DinosaurIsland"
Title="ActiveDinosaurList" Height="850" Width="245" WindowStyle="SingleBorderWindow" Icon="/DinosaurIsland;component/Icon1.ico" ResizeMode="NoResize" >
<Window.Resources>
<local:EnergyBarColorConverter x:Key="EnergyBarColorConverter"/>
<local:DinoStatusConverter x:Key="DinoStatusConverter"/>
<DataTemplate x:Key="DinosaurInfo">
<StackPanel Orientation="Vertical" >
<Label Name="DinosaurName" Margin="0,0,0,-8" Content="{Binding Path=PersonalName}"/>
<Label Name="DinosaurSpecies" Margin="0,0,0,-8" FontStyle="Italic" Content="{Binding Path=Specie}"/>
<Label Name="DinosaurStatus" Margin="0,0,0,-8" Content="{Binding Path=State, Converter={StaticResource DinoStatusConverter}}"/>
<Label HorizontalAlignment="Center" Margin="0,0,0,-2" Content="Energy" />
<ProgressBar Name="Health" Margin="0,0,0,10" HorizontalAlignment="Center" VerticalAlignment="Top" Width="160" Height="15"
Foreground ="{Binding Path=Health, Converter={StaticResource EnergyBarColorConverter}}" Value="{Binding Path=Health}" />
<Separator/>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid Width="210">
<ListView x:Name="DinoListView" Width="207" ItemsSource="{Binding Path=Dinosaurs}" HorizontalAlignment="Left" Margin="3,0,0,0">
<ListView.View>
<GridView>
<GridViewColumn Width="180" Header="Select Dinosaur" CellTemplate="{StaticResource DinosaurInfo}" />
</GridView>
</ListView.View>
</ListView>
</Grid>
这是恐龙课:
using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Text;
namespace DinosaurIsland
{
public class Dinosaur : INotifyPropertyChanged
{
public string _specie;
public string Specie
{
get { return _specie; }
set{_specie = value; RaisePropertyChanged("Specie");}
}
public int Age { get; set; }
public int Weight { get; set; }
public double Height { get; set; }
public int _health;
public int Health
{
get { return _health; }
set{_health = value; RaisePropertyChanged("Health");}
}
public double Water { get; set; }
public double FoodConsumed { get; set; }
public bool Sex { get; set; }
public string PersonalName { get; set; }
public System.Windows.Point Head = new System.Windows.Point();
public List<System.Windows.Point> Location { get; set; }
public double Length { get; set; }
public double Speed { get; set; }
public byte _state;
public byte State
{
get { return _state; }
set{_state = value; RaisePropertyChanged("State");}
}
public System.Windows.Point Goal = new System.Windows.Point();
public System.Windows.Point[] FoodLocation = new System.Windows.Point[5]; // The last five locations that the dino found food
public System.Windows.Point[] WaterLocation = new System.Windows.Point[5]; // The last five locations that the dino found water
// Constructor
public Dinosaur()
{
}
public event PropertyChangedEventHandler PropertyChanged;
//called when a property is changed
protected void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
}
这是ViewModel类:
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
namespace DinosaurIsland
{
public class ViewModel : INotifyPropertyChanged
{
public ViewModel()
{
this.Dinosaurs = new ObservableCollection<Dinosaur>();
for(int i = 0; i < MainWindow.Dinosaurs.Count; i++)
this.Dinosaurs.Add(new Dinosaur()
{
PersonalName = MainWindow.Dinosaurs[i].PersonalName,
Specie = MainWindow.Dinosaurs[i].Specie,
Health = MainWindow.Dinosaurs[i].Health,
State = MainWindow.Dinosaurs[i].State
});
}
public event PropertyChangedEventHandler PropertyChanged;
//called when a property is changed
public void RaisePropertyChanged(string PropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
private ObservableCollection<Dinosaur> _dinoList = new ObservableCollection<Dinosaur>();
public ObservableCollection<Dinosaur> Dinosaurs
{
get { return _dinoList; }
set { _dinoList = value; RaisePropertyChanged("Dinosaurs"); }
}
}
}
以下是调用窗口的方法:
// This is a global
public ViewModel vm = new ViewModel();
// ....
// Instantiate window
ViewModel vm = new ViewModel();
DinoListDialogBox.DataContext = vm;
DinoListDialogBox.Show();
这应该是拼图的所有部分。我错过了什么?
谢谢...我会在你之后命名一只恐龙。
答案 0 :(得分:1)
好的看了你的来源可以得到你的用例的解决方案。我确实建议正确检查MVVM。现在看来,正如我在聊天中提到的那样,你的项目在很多方面都违背了MVVM。
将您的当前实现放在一边,以使Dinosaurs
列表与ActiveDinosaurList
视图同步,这些是我所做的更改:
<强> MainWindow.xaml.cs:强>
1)将Dinosaurs
切换为ObservableCollection<T>
和属性。如
public static List<Dinosaur> Dinosaurs = new List<Dinosaur>();
到
public static ObservableCollection<Dinosaur> Dinosaurs { get; set; }
2)向MainWindow
类添加静态构造函数以初始化Dinosaurs
属性
static MainWindow() {
Dinosaurs = new ObservableCollection<Dinosaur>();
}
<强> ViewModel.cs 强>
3)将Dinosaurs
属性切换为pass-thru到MainWindow
中的静态属性,并删除后备集合。如
private ObservableCollection<Dinosaur> _dinoList = new ObservableCollection<Dinosaur>();
public ObservableCollection<Dinosaur> Dinosaurs
{
get { return _dinoList; }
set { _dinoList = value; RaisePropertyChanged("Dinosaurs"); }
}
到
public ObservableCollection<Dinosaur> Dinosaurs {
get {
return MainWindow.Dinosaurs;
}
}
4)最后添加一个钩子来收听来自CollectionChanged
的{{1}}上的MainWindow.Dinosaurs
以及ViewModel
属性RaisePropertyChanged
上的Dinosaurs
。
所以切换:
public ViewModel()
{
this.Dinosaurs = new ObservableCollection<Dinosaur>();
for(int i = 0; i < MainWindow.Dinosaurs.Count; i++)
this.Dinosaurs.Add(new Dinosaur()
{
PersonalName = MainWindow.Dinosaurs[i].PersonalName,
Specie = MainWindow.Dinosaurs[i].Specie,
Health = MainWindow.Dinosaurs[i].Health,
State = MainWindow.Dinosaurs[i].State
});
}
到
public ViewModel() {
MainWindow.Dinosaurs.CollectionChanged += (sender, args) => RaisePropertyChanged("Dinosaurs");
}
就是这样。现在运行您的模拟,当我转发时间时,我可以看到ActiveDinosaurs列表上的状态更新正常。
答案 1 :(得分:0)
在绑定中使用UpdateSourceTrigger=PropertyChanged
。
所以你的标签看起来像这样:<Label Name="DinosaurStatus" Margin="0,0,0,-8" Content="{Binding Path=State, Converter={StaticResource DinoStatusConverter} UpdateSourceTrigger=PropertyChanged}" />
。