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