我是MVVM的新手,我不明白。我到目前为止的代码:
在ItemListPage.xaml中:
<ListView ItemsSource="{Binding itemList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding itemSelected, Mode=TwoWay}"
ItemClick="{x:Bind ViewModel.ClickItemList}">
在ItemListViewModel.cs中:
private List<Item> _itemList;
public List<Item> itemList { get { return _itemList; } set { Set(ref _itemList, value); } }
private Item _itemSelected;
public Item itemSelected { get { return _itemSelected; } set { Set(ref _itemSelected, value); } }
public void ClickItemList()
{
System.Diagnostics.Debug.WriteLine("Click on itemlist");
if (itemSelected != null)
{
((App)App.Current)._itemID = itemSelected._ID;
NavigationService.Navigate(typeof(Views.ShowItem));
}
}
我遇到的问题是我第一次点击某个项目时,调用了函数ClickItemList,但属性itemSelected仍为空,所以我需要在项目上第二次单击以实际执行我想要执行的操作(保存此项目的ID并导航到下一页)。如何更改我的代码呢?
除了这个问题,我不明白为什么我应该使用2个属性(例如私有属性_itemSelected和public&#34; fake&#34;属性itemSelected),为什么我不能只使用一个?
答案 0 :(得分:2)
我遇到的问题是我第一次点击某个项目时,调用了函数ClickItemList,但属性itemSelected仍为空,所以我需要在项目上第二次单击以实际执行我想要执行的操作(保存此项目的ID并导航到下一页)。如何更改我的代码呢?
这是因为ListView将在引发ItemClick事件后更新SelectedItem 。如果您想知道单击了哪个项目,则需要访问事件参数:
public void ClickItemList(object sender, ItemClickEventArgs e)
{
var clickedItem = (Item)e.ClickedItem;
}
除了这个问题,我不明白为什么我应该使用2个属性(例如私有属性_itemSelected和公共“假”属性itemSelected),为什么我不能只使用一个?
只是为了澄清一些术语:
_itemList
是私有字段。itemList
是公共财产 *。属性只不过是一个getter和setter函数。字段实际上将对象存储在类的实例中。出于这个原因,公共属性通常会有一个私有支持字段,它委托它访问。
itemList
必须是公共属性才能绑定到它(通过{Binding}
)。如果您希望能够在运行时将itemList
更改为全新列表并让ListView自动更新其项目,那么您的视图模型必须实现INotifyPropertyChanged并在itemList
更改时引发PropertyChanged事件。这是您的属性的setter中发生的事情(感谢您拥有的帮助器Set
方法)。在这种情况下,您需要有一个私有字段来存储实际列表,并使用public属性确保在您更改itemList
时引发PropertyChanged。
将ListSource双向绑定是没有意义的(因为你有),因为ListView从不更改ItemsSource。事实上,如果您根本不更改itemList
,那么您可以像这样更改您的视图模型**:
// Generates a hidden private field automatically, and is used as if it were a public field
public List<Item> itemList { get; set; }
和XAML是这样的:
<ListView ItemsSource="{x:Bind ViewModel.itemList}" ItemClick="{x:Bind ViewModel.ClickItemList}">
*我建议通过命名以大写字母开头的公共属性来坚持Microsoft的惯例,例如ItemList
而不是itemList
。
** x:Bind也支持绑定到公共字段,而不仅仅是属性,但我建议始终在类的公共接口中使用属性,但这取决于你。
答案 1 :(得分:0)
有时私人财产不是必需的,他们的大部分用途是:
在“返回”或分配值之前需要进行一些处理。
当您需要或想要缓存或延迟加载属性时
当属性不是公共访问权限(冗余)时
因此,要回答您的问题,如果您的公共财产只是封装它,则不需要私有字段。举个例子。
private string _property;
public string Property {
get { return _property; }
set { _property = value; }
}
可以替换为:
public string Property { get; set; }
答案 2 :(得分:0)
其他两个答案都是正确的,但具体而言,第一次点击没有任何反应的原因是因为没有更改选择。
要解决这个问题,当您打开页面时(例如在构造函数中),您可以将SelectedItem
设置为itemList
的第一项,然后您的第一项应该正常工作。
答案 3 :(得分:0)
感谢您的所有答案,这有助于我更好地理解问题和MVVM模式。
我在这里找到的简单解决方案是在我的.xaml中将触发事件 ItemClick 更改为 SelectionChanged ,因为在ListView更新SelectedItem之前会引发ItemClick事件,但是之后会立即引发SelectionChanged事件。
现在它按预期工作:点击我的列表框中的项目=&gt;更新SelectedItem binded属性=&gt; SelectionChanged事件被触发=&gt;我的函数ClickItemList被调用并在保存所选项目的ID
后转到下一页