C# 当从视图X中的ListView选择填充视图Y时,为什么视图Y显示过时的结果?

C# 当从视图X中的ListView选择填充视图Y时,为什么视图Y显示过时的结果?,c#,wpf,mvvm,async-await,prism,C#,Wpf,Mvvm,Async Await,Prism,我正在进行一个项目,其中主窗口有4个视图。其中有两种观点令我烦恼 这有助于将项目想象成类似MS Outlook的东西,在左侧有一个列表,当选择一个条目时,右侧窗格将显示该视图的详细信息 不过,我的项目将有多个MyList。因此,就像在MS Word中一样,您一直在打开和编辑新文档,因此用户也将通过多个MyList 当前发生的情况是,从左窗格中选择的条目显示在右窗格中,但单击后面有一个选择。所以第一次选择不显示任何内容,下一次选择显示先前选择的项目,下一次选择显示先前选择的项目,等等 我用的是棱镜

我正在进行一个项目,其中主窗口有4个视图。其中有两种观点令我烦恼

这有助于将项目想象成类似MS Outlook的东西,在左侧有一个列表,当选择一个条目时,右侧窗格将显示该视图的详细信息

不过,我的项目将有多个MyList。因此,就像在MS Word中一样,您一直在打开和编辑新文档,因此用户也将通过多个MyList

当前发生的情况是,从左窗格中选择的条目显示在右窗格中,但单击后面有一个选择。所以第一次选择不显示任何内容,下一次选择显示先前选择的项目,下一次选择显示先前选择的项目,等等

我用的是棱镜6。我还使用名为ObservableImmutableList而不是ObservableCollection来处理视图的Listview对象

相关代码:

public ActiveMyListItemViewModel(IEventAggregator eventAgg) : BindableBase
{
    if (_eventAggregator == null && eventAgg != null)
    {
        _eventAggregator = eventAgg;
        _eventAggregator.GetEvent<ItemUpdateEvent>().Subscribe(setProperties);
    }
}

protected void setProperties(AbstractRepresentation abstract)
{
    try
    {
        setProperties(abstract.ID, abstract.name, [...]);
    }
    catch (NullReferenceException nre)
    {
        throw nre;
    }
}
MyList ViewModel:

public class MyListViewModel : BindableBase
{
    private MyListModel activeMyList;
    private IEventAggregator _eventAggregator;

    public MyListViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;

        _selectItemDelegateCommand = DelegateCommand<IList>.FromAsyncHandler(selectItem);

        //Simplified version of real method
        activeList = MyListModel.MyList.GetActiveListItem(_eventAggregator);
        ...
    }

    private DelegateCommand<System.Collections.IList> _selectItemDelegateCommand;

    /// <summary>
    /// Command associated with the selection of an item in the observableimmutablelist
    /// </summary>
    public DelegateCommand<System.Collections.IList> SelectItemDelegateCommand
    {
        get
        {
            return _selectItemDelegateCommand;
        }
        private set { _selectItemDelegateCommand = value; }
    }

    private async Task<int> selectItem(System.Collections.IList items)
    {
        var id = items.Cast<MyListItemViewModel>();

        _eventAggregator.GetEvent<ItemUpdateEvent>().Publish(MyListItems.FirstOrDefault(x => x.ItemID == id.First<MyListItemViewModel>().ID).toAbstractRepresentation());     

        return await Task.FromResult(1);
    }

    private readonly object _myListItemsLock;
    private ObservableImmutableList<MyListItemViewModel> _myListItems;
    public ObservableImmutableList<MyListItemViewModel> MyListItems
    {
        get { return _myListItems; }
        private set
        {
            lock (_myListItemsLock)
            {
                SetProperty(ref _myListItems, value);
            }
        }
    }
}
将其更改为该选项可使其立即工作

    protected String _txtDocName;
    public String TxtDocName
    {
        get { return _myModelItem.Name; }
        set
        {
            _txtDocName = value;
            _myModelItem.Name = value;
            OnPropertyChanged("TxtDocName");

        }
    }

然而,这太笨重了,并且删除了Prism所做的大量工作。解决这个问题的更好方法是什么?

你的问题是,你广播了一个事实:财产已经改变了,但当你还在做改变的时候,你正在做它。

例如:

protected String _txtDocName;
public String TxtDocName
{
    get { return _myModelItem.Name; }
    set
    {
        SetProperty(ref _txtDocName, value);
        _myModelItem.Name = _txtDocName;
    }
}
public String TxtDocName
{
    get { return _myModelItem.Name; }
    set
    {
        _myModelItem.Name = value;
        SetProperty(ref _txtDocName, value);
    }
}
SetProperty
触发属性更改通知,WPF获取通知,查询值,但它仍然是旧值。只有在WPF查询新值之后,您才真正更改您所说的已经更改的值

那么你如何修复它呢?最好的选择是重写属性,在设置所有字段后触发属性更改。例如:

protected String _txtDocName;
public String TxtDocName
{
    get { return _myModelItem.Name; }
    set
    {
        SetProperty(ref _txtDocName, value);
        _myModelItem.Name = _txtDocName;
    }
}
public String TxtDocName
{
    get { return _myModelItem.Name; }
    set
    {
        _myModelItem.Name = value;
        SetProperty(ref _txtDocName, value);
    }
}
或者,您可以在更改字段后简单地调用:

public String TxtDocName
{
    get { return _myModelItem.Name; }
    set
    {
        _txtDocName = value;
        _myModelItem.Name = _txtDocName;
        OnPropertyChanged();
    }
}

请注意,您不必将任何内容传递到
OnPropertyChanged()
,因为该方法在
propertyName
参数上具有
CallerMemberNameAttribute
,允许您在属性名称与当前属性相同的情况下忽略它。

创建区域视图X。在选择列表框时,请使用PRISM IRegionManager.Request导航到其他视图。非常感谢您的响应。条目详细信息视图始终可见。我不是导航到它,我只是填充它。为什么我应该使用RegionManager导航命令?为什么selectItems是异步的?主要是因为我最初从代码早期版本的其他地方获取了AbstractRepresentation。然而,我确实测试了没有async Wait功能的代码,它的行为完全相同。你能在一个小样本项目中重现这个问题吗??还记得在评论中提到用户名,这样用户会得到通知。例如:如果你想通知我一些事情,只需使用@Vishal,然后键入你的评论。这将通知我您已回复我。在第一个解决方案中,您希望使用
\u myModelItem.Name=value
(不是
\u myModelItem.Name=\u txtDocName;
),否则您将在此处获得旧值…@Haukinger问题海报。好主意,我自己也抓到了:)明天我会发布更多的信息和我的想法。麦基,很好的分析,非常感谢!您的回答是正确的,并允许我重新介绍Prism eventnotifier。谢谢!