Prism MVVM模式:View在ViewModel中的属性更改方面总是落后一步

时间:2014-08-30 12:00:10

标签: vb.net mvvm windows-store-apps prism inotifypropertychanged

在Prism,MVVM,Windows 8.1 StoreApp中,我希望ViewModel捕获ListView中的SelectItem。 ListView包含ObservableCollection对象。 ViewModel需要查找所选对象的更多详细信息并通知View。 View依次显示对象的细节。

我已实现此功能,但View allways显示前一个对象(选择新对象后)

当然,我所寻找的是在选择对象的视图中立即和正确的反应。这是我的代码片段,所有代码都在VB代码中。

编辑:我已经提出了另一个 - 更小的例子,使用这种方法。我记录了这个过程in this video. 请在进一步阅读之前先看一下!!

对象来自ViewModel:

  

Public Property Persons As New ObservableCollection(Of Person)

它们绑定到用户控件:

<Grid>
    <ListView 
                ItemsSource="{Binding Persons}" 
                ItemTemplate="{StaticResource BusinessCard}">
        <Interactivity:Interaction.Behaviors>
            <Core:EventTriggerBehavior EventName="SelectionChanged">
                <Behaviors:ListViewSelectionChangedAction/>
            </Core:EventTriggerBehavior>
        </Interactivity:Interaction.Behaviors>
    </ListView>
</Grid>

通过行为最终通过此代码终止于ViewModel:

Sub New(InjectedEventAggregator As IEventAggregator)

        LocalEventAggregator = InjectedEventAggregator
        LocalEventAggregator.GetEvent(Of PersonIsSelectedEvent)().Subscribe(AddressOf HandlePersonIsSelected, True)

此事件由此例程处理

    Public Sub HandlePersonIsSelected(ByVal SelectedPerson As Person)
        ActualPerson = SelectedPerson
    End Sub

所有这一切的最后一部分是包含ActualPerson的属性,如下所示:

    Private Property _ActualPerson As Person
    Public Property ActualPerson As Person
        Get
            Return _ActualPerson
        End Get
        Set(value As Person)
            SetProperty(_ActualPerson, value)
        End Set
    End Property

编辑:,这是应该显示所选ActualPerson的XAML:

<StackPanel DataContext="{Binding ActualPerson}" >

       <Image Source="{Binding Photo}" Stretch="Fill" />

       <StackPanel Orientation="Horizontal">
           <TextBlock Text="{Binding FirstName}" />
           <TextBlock Text="{Binding FamilyName}" />
           <TextBlock Text="{Binding Gender}" />
       </StackPanel>

</StackPanel>

当我单步执行代码时,我可以看到在ViewModel中捕获了SelectedItem事件,调用了所选人员的处理程序,更新了属性。使用Prism也意味着会触发NotifyPropertyChanged事件。它确实被解雇了,否则前一个对象不会显示我猜。

但为什么View没有使用正确的(Person)对象立即更新?

如果你有线索......那是我的贵宾!

此致

3 个答案:

答案 0 :(得分:0)

让我试着理解你所说的内容&#34;对View&#34;没有反应。你是说UI没有改变,即使&#39; ActualPerson = SelectedPerson&#39;叫做?

控件有一个名为MODE的绑定属性,用于决定数据流。显示人员信息的TextBlocks的MODE可以是 OneWay 。绑定可能是 OneTime ,这会导致问题。

答案 1 :(得分:0)

您能否确认来自您的存储库的内容?我假设它不是一个可观察的集合。至少它不应该,我认为它将是一个可序列化的POCO对象。这意味着您需要将项添加到observable集合中。如果不使用CollectionView,我这样做的方法是拥有一个ObservableCollection类型的只读变量,它永远不会改变。然后,当您对消息发出请求时,我会确保清除集合,为新项目做好准备。一旦返回消息,循环遍历响应中的每个模型项(消息)并将它们转换为MessageViewModels(一个包含可绑定属性和验证(数据注释)的新类。)当每个ViewModel项创建时,它将被添加到observablecollection。向集合添加项目的行为将引发listview正在侦听的事件,因此将显示该项目(只要MessageViewModel具有关联的数据模板。

private readonly _messages = new ObservableCollection<MessageViewModel>(); 

Public ObservableCollection<MessageViewModel> Messages {get { return _messages;}} 

OnNavigateTo

Messages.Clear; 
foreach(var message in await _messageRepository,GetMessagesAsync()) 
{ 
    Messages.Add(new MessageViewModel(){Name = message.Name, Text = message.Text}); 
} 

这有意义吗?

答案 2 :(得分:0)

一个糟糕的解决方案,但也许它很有帮助。你可以再次打电话给#34; OnProperyChanged。我再次说&#34;&#34;因为假设SetProperty调用它,但我也遇到了VB.NET和SetProperty的一些问题。

Private Property _ActualPerson As Person
Public Property ActualPerson As Person
    Get
        Return _ActualPerson
    End Get
    Set(value As Person)
        SetProperty(_ActualPerson, value)
        OnPropertyChanged("ActualPerson")
    End Set
End Property

2015年2月4日编辑:好的解决方案在这里:OnPropertyChanged not fired when SetProperty is called

简单地删除单词&#34; Property&#34;在私人声明中。这是因为它传递了ByRef,因此它不能成为属性。