我想使用Caliburn.Micro MVVM创建一个WPF应用程序。其中的一个View应该对ViewModel获得的数据进行漂亮的绘制。在View中,我想在后面的代码中进行绘制。我使用标量依赖属性。这很好用。我也可以使用存储在BindableCollection中的数据(下面例子代码中的LocationList)。不起作用的是,如果我向BindableCollection中添加新元素,就会更新DependencyProperty。这一定是一个愚蠢的错误,但我没有看到它。我创建了一个演示应用程序,尽可能地省略了很多内容。这是一个标准的Caliburn.Micro设置。我没有在这里显示Bootstrapper、ShellView和ShellViewModel。它们是一般的入门配置。
ViewModel是这样的。
using Caliburn.Micro;
using System.Collections.Generic;
namespace BindingCodeBehind.ViewModels
{
public class DemoViewModel : Screen
{
private BindableCollection<string> _locationList;
public BindableCollection<string> LocationList
{
get { return _locationList; }
set
{
_locationList = value;
NotifyOfPropertyChange(()=>LocationList);
}
}
public DemoViewModel()
{
LocationList = new BindableCollection<string>();
}
protected override void OnViewLoaded(object view)
{
base.OnViewLoaded(view);
for (int i = 0; i < 3; i++)
{
// BindableCollection supports AddRange, but not Add.
LocationList.AddRange( new List<string>{$"Test nr {i}"});
// LocationList.Add($"Test nr {i}");
}
NotifyOfPropertyChange(()=>LocationList.Count);
}
}
}
LocationList
在构造函数中被初始化。我在 OnViewLoaded
事件处理程序。
视图的XAML代码没有什么特别的,只是一个脚手架式的 UserControl
,什么也没加。后面的代码是这样的。
using Caliburn.Micro;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
namespace BindingCodeBehind.Views
{
public partial class DemoView : UserControl
{
public BindableCollection<string> LocationList
{
get { return (BindableCollection<string>) GetValue(LocationListProperty); }
set { SetValue(LocationListProperty, value);}
}
public static readonly DependencyProperty LocationListProperty =
DependencyProperty.Register("LocationList",
typeof(BindableCollection<string>),
typeof(DemoView),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnLocationListChanged)));
public DemoView()
{
InitializeComponent();
var myBinding = new Binding
{
Mode = BindingMode.TwoWay,
Path = new PropertyPath("LocationList"),
NotifyOnSourceUpdated = true
};
BindingOperations.SetBinding(this, LocationListProperty, myBinding);
}
protected override void OnRender(DrawingContext drawingContext)
{
// Data from LocationLst should be used in drawing
}
private static void OnLocationListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// I assume this called if LocationList changes
}
}
}
在代码中,有一个依赖属性 LocationList
被创建。在构造函数中,我为这个属性创建了一个绑定。在调试器中,我看到这实际上是有效的。OnLocationListChanged
如果这个列表发生变化,应该调用这个函数。我看到当我创建 LocationList
的构造函数中,但当我在ViewModel中添加三个元素时,句柄没有被再次调用。LocationList
. 因此,我认为问题出在了对 INotifyChange
. 为了更好的理解,我查了一下源代码的 BindableCollection
课堂上,看到 Add
方法没有实现,所以我在ViewModel中修改了我的代码,使用了 AddRange
方法,只是为了确定,但它没有帮助。
我试了很多办法,但是我完全没有办法让这个事情成功。我真的希望有人能帮助我。基本上,所有这些都应该导致我的应用程序的调用。OnRender
再次更新绘图。这是我的第一个WPF绘图应用,也是我的第一个Caliburn.Micro应用,所以这一切对我来说还是很陌生的。
我的开发环境。Visual Studio 2019, 社区版, .Net Core 3.1 C# 8.0, Windows10. 都是用最新的补丁更新的。
你的假设是"如果这个列表发生变化,应该调用OnLocationListChanged。"是错误的。
依赖属性的回调只有在属性本身被设置为新的值时才会被调用,也就是当你将它分配给一个新的 BindableCollection<string>
.
当你在收藏中添加或删除物品时,它不会被调用。有一个 CollectionChanged
事件,你可以处理到响应个别项目被添加或删除。