[英]Bound property in WPF doesn't update
我的WPF / MVVM(带有MVVM Light框架)游戏中有一个TextBlock
,它绑定到一个应该反映雇佣工人数量的属性。 我已经确认绑定是完整的,但我无法更新它。
这是我视图中的TextBlock
:
<TextBlock x:Name="WorkersTextBlock"
FontFamily="Pericles"
DataContext="{Binding Guilds[0]}"
Text="{Binding Workers.Count,
StringFormat=Workers : {0},
FallbackValue=Workers : 99}" />
我的viewmodel中的属性:
public ObservableCollection<Guild> Guilds
{
get { return DataManager.Data.Guilds; }
}
同样在我的viewmodel中,更改Worker
的Employer属性的命令:
private void ExecuteHireWorkerCommand()
{
if (SelectedWorker == null)
return;
SelectedWorker.Employer = DataManager.Data.Guilds[0];
Gold -= SelectedWorker.Salary;
_workerCollectionView.Refresh();
}
在DataManager中,它是一个包含所有数据的单例类:
private ObservableCollection<Guild> _guilds = new ObservableCollection<Guild>();
public ObservableCollection<Guild> Guilds
{
get { return _guilds; }
}
private ObservableCollection<Worker> _workers = new ObservableCollection<Worker>();
public ObservableCollection<Worker> Workers
{
get { return _workers; }
}
在Guild
模型中:
public ObservableCollection<Worker> Workers
{
get { return DataManager.Data.Workers.Where(w => w.Employer == this).ToObservableCollection(); }
}
Worker
的雇主财产是:
public Guild Employer { get; set; }
最后,我的扩展方法(我认为是问题的根源):
public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> source)
{
if (source == null)
{
throw new ArgumentNullException("source");
}
return new ObservableCollection<T>(source);
}
Messageboxes确认通过该命令,正在更新Worker
的'Employer属性,但我尝试过的任何内容都不会使TextBlock
更新。 我已经尝试在我列出的所有内容上实现RaisePropertyChanged
而没有运气。
如果我在初始化数据时将Worker
的Employment属性设置为构造函数中的正确的guild,则TextBlock
的数字会正确显示,但之后不会更新。 我的预感是Workers
属性中的LINQ过滤和扩展方法导致了这个麻烦,但我可能是错的。
如果有人对如何让它发挥作用有任何想法,我很乐意听到它们。 任何有关此事的建议都将不胜感激。 如果您需要更多代码或信息,请询问。
谢谢。
更新:我认为罗恩正走在正确的道路上; 扩展方法可能会打破绑定。 如果是这种情况,任何人都可以给我任何关于如何过滤Guild
的Workers属性而不破坏绑定的建议吗? 此外,就setter问题而言,我在Workers属性中添加了一个setter,但它实际上从未触发过。
public ObservableCollection<Worker> Workers
{
get { return DataManager.Data.Workers.Where(w => w.Employer == this).ToObservableCollection(); }
}
当此属性实际更改时,您不会通知绑定系统。 如果基础集合本身发生了变化,你会没事的。 但是你甚至没有保留对该底层集合的引用 - 你只是返回它。
正常模式会是这样的(假设您在Guild
实现了INotifyPropertyChanged
)
private ObservableCollection<Worker> _Workers;
public ObservableCollection<Worker> Workers
{
get { return _Workers; }
set
{
if (value != _Workers)
{
_Workers = value;
NotifyPropertyChanged("Workers")
}
}
}
但这在某种程度上取决于你如何设置对象。 无论如何,您需要通知系统集合正在以某种方式发生变化。
编辑:你在评论中提到你使用了魔法。 我去看了文档。 它说如何运作
5)显式或隐式应用MagicAttribute转换所有可用的公共属性的setter。
你没有在该属性上设置setter,所以它不会修复它。
我认为你需要重新设计基础数据结构。 但尽管如此,您可以稍微改变它以使其工作。
将Workers
属性更改为ICollectionView
如下所示:
public ICollectionView Workers { get; set; }
然后在Guild模型的contstructor中,您可以从数据管理器填充workers集合,如下所示:
Workers = CollectionViewSource.GetDefaultView(DataManager.Data.Workers);
并向您的ICollectionView
添加一个过滤器,如下所示:
Workers.Filter = (worker) => { return (worker.Employer == this); };
每当更新Workers
集合时调用Workers.Refresh()
。
这样你的绑定就不会破坏,你的Workers
集合将保留相同的实例。
哦,并将UpdateSourceTrigger=PropertyChanged
添加到TextBox
绑定中。
就像我说的那样,我会考虑完全重新设计支持数据结构,但不知道为什么或如何实现它我不能说更多。
我还没有测试过你的代码,但是在Guild
模型中,返回一个new ObservableCollection
(可以在你的扩展方法中看到)可能会破坏你的绑定 ,我建议稍微重新设计一下,以便绑定视图始终与原始视图相关联ObservableCollection
实例。
虽然我没有使用你的框架,但是当我实现MVVM模式时,我总是确保我的ViewModel的observable仍然是同一个实例,并且我使用Clear
方法来替换我的OnModelChanged
方法中的内容,这样你就不会必须处理警告视图这些更改所需的通知,它由ObservableCollection
处理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.