【发布时间】:2013-12-13 20:41:19
【问题描述】:
我有一个 WinRT 应用程序,其中包含许多用户、项目、会议等。
我有一个主屏幕,带有一个主屏幕视图模型,它应该显示 CurrentUser 并且有一个绑定到 CurrentUser.ProjectList 的 ListView。
我在 ViewModel 中使用 UserProvider 类初始化 CurrentUser,该类从数据库中获取所有必需的信息。
然后我的问题变得与此非常相似:Subscribe to INotifyPropertyChanged for nested (child) objects
我有一个用户和项目模型:
public class User
{
public int id { get; set; }
public string ForeName { get; set; }
public string Surname { get; set; }
... etc ...
public ObservableCollection<Project> ProjectList { get; set; }
public ObservableCollection<User> FriendList { get; set; }
... constructor
}
public class Project
{
public String Name { get; set; }
public int Id { get; set; }
public List<User> Users { get; set; }
public List<Meeting> Meetings { get; set; }
.. constructor ...
}
具有以下内容的视图模型:
class HomeScreenViewModel : INotifyPropertyChanged {
private User _currentUser;
public User CurrentUser
{
get { return this._currentUser; }
set
{
if (Equals(_currentUser, value)) return;
this._currentUser = value;
RaisePropertyChanged("CurrentUser");
}
}
//[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
...我在这个视图模型中有一个获取当前用户的方法
public async Task<bool> GetLoggedInUserAsync()
{
int testId = 0;
CurrentUser = await userProvider.GetCurrentUser(testId);
UserProjects = await userProvider.GetUsersProject(CurrentUser);
CurrentUser.ProjectList = UserProjects;
return true;
}
在视图的 loadState 中调用
public MainPage()
{
this.InitializeComponent();
addMeeting = new AddMeetingFlyout();
_vm = new HomeScreenViewModel();
this.DataContext = _vm;
}
protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
{
await _vm.GetLoggedInUserAsync()
}
我在 XAML 中的绑定,例如 ProjectList 和 ForeName,如下所示:
<CollectionViewSource
x:Name="projectsViewSource"
Source="{Binding CurrentUser.ProjectList}"/>
...
<ListView
x:Name="projectList"
ItemsSource="{Binding Source={StaticResource projectsViewSource}}"
Grid.Row="1"
SelectionMode="None"
Style="{StaticResource DraggableListView}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
IsItemClickEnabled="True"
>
<ListView.ItemTemplate>
<DataTemplate>
<Button Style="{StaticResource ProjectTileButton}" Content="{Binding Name}" Click="ProjectItem_Click" />
</DataTemplate>
</ListView.ItemTemplate>
<AddDeleteThemeTransition/>
</ListView>
...
<Button ...>
<TextBlock ...">
<Run Text="{Binding CurrentUser.ForeName}" />
</TextBlock>
</Button>
按钮内容 CurrentUser.ForeName 会在 CurrentUser 首次在视图模型中初始化时触发 INotifyPropertyChanged 事件。这反映在视图中 - 但对 CurrentUser.ForeName 的任何进一步更改都不会触发任何后续 INotifyPropertyChanged 事件。 ProjectList 也不会显示在视图中,并且不会触发 INotifyPropertyChanged 事件,即使我知道它存在。
我花了很多天时间研究实现 INotifyPropertyChanged,以便对嵌套子复杂对象(例如 CurrentUser.ProjectList)的更改将传播到视图。目前,发生这种情况的唯一方法是如果我强制调用
this._currentUser = value;
RaisePropertyChanged("CurrentUser");
我正在使用一个在视图模型中调用 MakeChange() 方法的按钮进行测试
public void MakeChange()
{
User updatedCurrentUser = CurrentUser;
CurrentUser = updatedCurrentUser;
}
这行得通,所以我知道事实上所有数据都正确地来自数据库,而且一切都是应有的 - 少了一件需要担心的事情!
但是,我根本无法让视图在页面加载或添加新项目时显示用户项目。
我尝试实施此解决方案:https://gist.github.com/thojaw/705450,但是,WinRT 反射功能发生了变化,我不确定如何让以下留置权在我的项目上下文中工作,因为这超出了我的范围:
//from property
//in _type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
//where _inotifyType.IsAssignableFrom(property.PropertyType)
//select property;
任何帮助将不胜感激 - 老实说,我认为我所要做的就是将 CurrentUser.ProjectList 绑定到 ListView。
【问题讨论】:
标签: xaml binding windows-runtime viewmodel inotifypropertychanged