【问题标题】:Have complex object update in view when property changed - property changed event not fired - WinRT/XAML属性更改时查看复杂对象更新 - 未触发属性更改事件 - WinRT/XAML
【发布时间】: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


    【解决方案1】:

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

    有一个很好的例子here

    【讨论】:

      猜你喜欢
      • 2011-02-08
      • 2011-06-01
      • 2012-05-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多