数据绑定 ObservableCollections 与 IoC
Data Binding ObservableCollections with an IoC
我正在编写一个针对 Windows 8.1 的通用应用程序,并且正在重写它以使用 IoC 容器。但是,我发现了一些让我有点困惑的事情。
在我使用 IoC 之前,我会在代码隐藏中创建我的 VM 实例并绑定到它,如下所示:
MainPage.xaml
<ListBox ItemsSource="{Binding ItemList}" DisplayMemberPath="Title" />
MainPage.xaml.cs
private MainPageVM Data = new MainPageVM();
public MainPage()
{
this.InitializeComponent();
this.DataContext = Data;
}
MainPageVM.cs
public ObservableCollection<MenuItem> ItemList { get; set; }
public MainPageVM()
{
ItemList = new ObservableCollection<MenuItem>();
}
这很好用。但是,现在我设置应用程序的方式非常不同,如下所示:
App.xaml.cs
private IUnityContainer _Container;
public App()
{
_Container = new UnityContainer();
this.InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
_Container.RegisterType<MainPage>(new ContainerControlledLifetimeManager());
_Container.RegisterType<Frame>(new ContainerControlledLifetimeManager());
_Container.RegisterType<MainPageVM>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(typeof(Frame),
typeof(MainPage)));
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = _Container.Resolve<Frame>();
rootFrame.CacheSize = 1;
}
if (rootFrame.Content == null)
{
var mainPageVM = _Container.Resolve<MainPageVM>();
mainPageVM.Show();
}
Window.Current.Activate();
}
这会创建一个 MainPageVM()
的实例:
MainPageVM.cs
private Frame _Frame;
private Page _View;
public ObservableCollection<MenuItem> ItemList { get; set; }
public MainPageVM(
Frame frame,
Page view)
{
_Frame = frame;
_View = view;
_View.DataContext = this;
ItemList = new ObservableCollection<MenuItem>();
OnPropertyChanged("ItemList");
}
public void Show()
{
_Frame.Content = _View;
Window.Current.Content = _Frame;
}
MainPage.xaml.cs
public MainPage()
{
this.InitializeComponent();
}
MainPage.xaml没变。
我的问题是,为什么我必须在第二个版本而不是第一个版本中发出 OnPropertyChanged("ItemList");
信号来激活绑定?我是不是做错了什么?
我的整个存储库可以在 GitHub 上找到:Learn OneNote。
在这两行之间切换应该可以解决这个问题:
_View.DataContext = this;
和
ItemList = new ObservableCollection<MenuItem>();
发生的情况是您当前首先设置 DataContext,这会导致重新评估所有视图的绑定,然后才修改 ItemsList
。由于 ItemsList
的 setter 不调用 OnPropertyChanged
,视图在更改时不会更新。通过在行之间切换,您首先初始化数据上下文,然后才重新评估绑定。
一个更具可读性的解决方案是在您的 setter 中包含对 OnPropertyChanged
的调用(这样您就不必换行):
private ObservableCollection<MenuItem> itemList
public ObservableCollection<MenuItem> ItemList
{
get { return itemsList; }
set
{
if (itemsList != value)
{
itemsList = value;
OnPropertyChanged("ItemsList");
}
}
}
虽然最好先初始化数据上下文,然后再设置它以避免控件尝试绑定两次。
这是因为在第一个版本中,ItemList 在视图模型构造函数中实例化,视图模型构造函数本身在数据绑定之前在视图初始化时构造。但是在第二个版本中,首先绑定数据,然后实例化 ItemList。
我正在编写一个针对 Windows 8.1 的通用应用程序,并且正在重写它以使用 IoC 容器。但是,我发现了一些让我有点困惑的事情。
在我使用 IoC 之前,我会在代码隐藏中创建我的 VM 实例并绑定到它,如下所示:
MainPage.xaml
<ListBox ItemsSource="{Binding ItemList}" DisplayMemberPath="Title" />
MainPage.xaml.cs
private MainPageVM Data = new MainPageVM();
public MainPage()
{
this.InitializeComponent();
this.DataContext = Data;
}
MainPageVM.cs
public ObservableCollection<MenuItem> ItemList { get; set; }
public MainPageVM()
{
ItemList = new ObservableCollection<MenuItem>();
}
这很好用。但是,现在我设置应用程序的方式非常不同,如下所示:
App.xaml.cs
private IUnityContainer _Container;
public App()
{
_Container = new UnityContainer();
this.InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
_Container.RegisterType<MainPage>(new ContainerControlledLifetimeManager());
_Container.RegisterType<Frame>(new ContainerControlledLifetimeManager());
_Container.RegisterType<MainPageVM>(
new ContainerControlledLifetimeManager(),
new InjectionConstructor(typeof(Frame),
typeof(MainPage)));
Frame rootFrame = Window.Current.Content as Frame;
if (rootFrame == null)
{
rootFrame = _Container.Resolve<Frame>();
rootFrame.CacheSize = 1;
}
if (rootFrame.Content == null)
{
var mainPageVM = _Container.Resolve<MainPageVM>();
mainPageVM.Show();
}
Window.Current.Activate();
}
这会创建一个 MainPageVM()
的实例:
MainPageVM.cs
private Frame _Frame;
private Page _View;
public ObservableCollection<MenuItem> ItemList { get; set; }
public MainPageVM(
Frame frame,
Page view)
{
_Frame = frame;
_View = view;
_View.DataContext = this;
ItemList = new ObservableCollection<MenuItem>();
OnPropertyChanged("ItemList");
}
public void Show()
{
_Frame.Content = _View;
Window.Current.Content = _Frame;
}
MainPage.xaml.cs
public MainPage()
{
this.InitializeComponent();
}
MainPage.xaml没变。
我的问题是,为什么我必须在第二个版本而不是第一个版本中发出 OnPropertyChanged("ItemList");
信号来激活绑定?我是不是做错了什么?
我的整个存储库可以在 GitHub 上找到:Learn OneNote。
在这两行之间切换应该可以解决这个问题:
_View.DataContext = this;
和
ItemList = new ObservableCollection<MenuItem>();
发生的情况是您当前首先设置 DataContext,这会导致重新评估所有视图的绑定,然后才修改 ItemsList
。由于 ItemsList
的 setter 不调用 OnPropertyChanged
,视图在更改时不会更新。通过在行之间切换,您首先初始化数据上下文,然后才重新评估绑定。
一个更具可读性的解决方案是在您的 setter 中包含对 OnPropertyChanged
的调用(这样您就不必换行):
private ObservableCollection<MenuItem> itemList
public ObservableCollection<MenuItem> ItemList
{
get { return itemsList; }
set
{
if (itemsList != value)
{
itemsList = value;
OnPropertyChanged("ItemsList");
}
}
}
虽然最好先初始化数据上下文,然后再设置它以避免控件尝试绑定两次。
这是因为在第一个版本中,ItemList 在视图模型构造函数中实例化,视图模型构造函数本身在数据绑定之前在视图初始化时构造。但是在第二个版本中,首先绑定数据,然后实例化 ItemList。