我有一个WinRT应用程序,包含许多用户,项目,会议等。
我有一个主屏幕,有一个主屏幕视图模型,它应该显示CurrentUser并且有一个绑定到CurrentUser.ProjectList的ListView。
我使用UserProvider类初始化ViewModel中的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>
当在Viewmodel中首次初始化CurrentUser时,按钮内容CurrentUser.ForeName会触发INotifyPropertyChanged事件。这反映在视图中 - 但对CurrentUser.ForeName的任何进一步更改都不会触发任何后续的INotifyPropertyChanged事件。 ProjectList也不会显示在视图中,即使我知道它存在,也不会触发INotifyPropertyChanged事件。
我花了很多天时间考虑实现INotifyPropertyChanged,以便对嵌套的子复杂对象(例如CurrentUser.ProjectList)的更改将传播到视图。在那一刻,发生这种情况的唯一方法就是强行拨打
this._currentUser = value;
RaisePropertyChanged("CurrentUser");
我正在使用一个按钮来测试,该按钮在viewmodel中调用一个名为MakeChange()的方法
public void MakeChange()
{
User updatedCurrentUser = CurrentUser;
CurrentUser = updatedCurrentUser;
}
这是有效的,所以我知道所有的数据都是从数据库中正确传出的,而且一切都应该是 - 不用担心了!
但是,我无法让视图在页面加载时显示用户项目,或者在添加新项目时。
我尝试实现这个解决方案:https://gist.github.com/thojaw/705450但是,WinRT反射功能已经改变,我不知道如何在我的项目环境中使用以下留置权,因为这超出了我的范围:< / p>
//from property
//in _type.GetProperties(BindingFlags.Instance | BindingFlags.Public)
//where _inotifyType.IsAssignableFrom(property.PropertyType)
//select property;
任何帮助都将不胜感激 - 老实说,我所要做的就是将CurrentUser.ProjectList绑定到ListView。