如何绑定ViewModel而非页面?ViewCell的OnDelete命令绑定问题求助
我来给你捋捋这个问题,你遇到的是Xamarin.Forms里很常见的绑定上下文层级问题——ViewCell默认继承了ItemTemplate的上下文(也就是单个IssueModel实例),所以直接绑OnDelete肯定找不到,因为命令在你的IssuePageModel里对吧?不用把命令塞进IssueModel里,咱们有更优雅的办法,直接在绑定命令的时候指定正确的数据源就行,下面给你两种常用方案:
方案一:用RelativeSource绑定到上级ListView的BindingContext
这是最推荐的方式,通过RelativeSource找到ListView的实例,然后取它的BindingContext(也就是你的IssuePageModel),这样就能直接访问OnDelete命令了,同时还能保留ViewCell对当前IssueModel的绑定:
<ListView ItemsSource="{Binding Issues}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <!-- 这里保留对IssueModel字段的绑定,比如标题 --> <Label Text="{Binding Title}" /> <!-- 删除按钮绑定到IssuePageModel的OnDelete命令 --> <Button Text="删除" Command="{Binding BindingContext.OnDelete, RelativeSource={RelativeSource AncestorType={x:Type ListView}}}" CommandParameter="{Binding .}" /> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView>
- 解释:
RelativeSource={RelativeSource AncestorType={x:Type ListView}}告诉绑定系统去查找最近的ListView父元素,然后BindingContext.OnDelete就是取这个ListView的BindingContext(也就是你的IssuePageModel)里的OnDelete命令。 CommandParameter="{Binding .}"把当前的IssueModel实例传给命令,这样你在命令逻辑里就能知道要删除哪一项了。
方案二:用x:Reference直接引用页面
如果你的页面有命名(比如给ContentPage加x:Name="IssuePage"),也可以直接通过引用页面来获取它的BindingContext:
<ContentPage x:Name="IssuePage" ...> <ListView ItemsSource="{Binding Issues}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Label Text="{Binding Title}" /> <Button Text="删除" Command="{Binding BindingContext.OnDelete, Source={x:Reference IssuePage}}" CommandParameter="{Binding .}" /> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
注意:这种方式要避免循环引用问题,比如不要在页面的BindingContext里直接引用页面本身。
关于你遇到的标记扩展错误
你提到的Invalid markup extension: expected type is object, actual type is Issuepagemodel错误,大概率是尝试直接把IssuePageModel类型作为绑定源导致的——绑定源需要的是实例,而不是类型。比如如果错误代码类似Source={x:Type pageModels:IssuePageModel},这就错了,因为x:Type返回的是类型,不是实例。上面两种方案都是引用已经存在的实例(ListView或者页面),就能避开这个问题。
另外提醒一句:不要直接修改ViewCell的BindingContext,那样会破坏ItemTemplate里对IssueModel字段的绑定(比如标题、状态这些显示内容都会失效),咱们要做的是给命令绑定单独指定数据源,而不是替换整个ViewCell的上下文。
内容的提问来源于stack exchange,提问作者JsonDork

