当属性更改时,视图中的复杂对象更新 - 未触发属性更改事件 - WinRT / XAML

时间:2013-11-28 00:02:06

标签: xaml binding windows-runtime viewmodel inotifypropertychanged

我有一个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。

1 个答案:

答案 0 :(得分:1)

当您要替换整个ObservableCollection本身时,您还需要为集合属性引入另一个属性更改事件和支持字段。

有一个很好的例子here