x:将ViewModel方法绑定到DataTemplate中的Event
我基本上问的是和这个人一样的问题,但是在新的x:Bind
的背景下。
ViewModels的DataContext定义如下
因此,每当我需要绑定某些东西时,我就会明确地对ViewModel这样做
ItemsSource="{x:Bind ViewModel.pageList, Mode=OneWay}"
但是,这在模板中不起作用
<-- this here is the culprit
阅读文档,我发现使用Path
应该基本上将上下文重置为页面,但是这个( x:Bind Path=ViewModel.PageResizeEvent
也不起作用。我仍然Object reference not set to an instance of an object
,这应该意味着它没有看到方法(但是null)。
图像类:
public class Image { public int page { get; set; } public string url { get; set; } public int width { get; set; } public int heigth { get; set; } }
并在ChapterPageViewModel中
private List _pageList; public List pageList { get { return _pageList; } set { Set(ref _pageList, value); } } public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode, IDictionary suspensionState) { Initialize(); await Task.CompletedTask; } private async void Initialize() { pageList = await ComicChapterGet.GetAsync(_chapterId); } public void PageResized(object sender, SizeChangedEventArgs e) { //resizing logic happens here }
我们这里有两个问题:
首先, 尝试将事件直接绑定到事件处理程序委托
简单地说,这将永远不会奏效。
处理MVVM模式事件的一种方法是使用EventTrigger和ICommand。
它需要一个实现ICommand的类。 如果不知道如何操作, 这篇文章将对你有所帮助。 我会打电话给我的DelegateCommand
。
以下是我将通过两个步骤重构它的方法:
1)向VM添加命令:
public class ChapterPageViewModel { public ChapterPageViewModel() { this.PageResizedCommand = new DelegateCommand(OnPageResized); } public DelegateCommand PageResizedCommand { get; } private void OnPageResized() { } }
2)使用EventTrigger和InvokeCommandAction将该命令绑定到SizeChanged事件。
(...)
“但加布里埃尔” ,你说, “那不起作用!”
我知道! 这是因为第二个问题,即试图x:绑定一个不属于DataTemplate类的属性
这个与这个问题密切相关,所以我会从那里借一些信息。
从MSDN,关于DataTemplate和x:Bind
在DataTemplate内部(无论是用作项目模板,内容模板还是标题模板),Path的值不会在页面的上下文中解释,而是在被模板化的数据对象的上下文中解释。 因此,在编译时可以validation其绑定(以及为它们生成有效的代码),DataTemplate需要使用x:DataType声明其数据对象的类型。
因此,当您执行
,您实际上是在该models:Image
上搜索名为ViewModel的属性models:Image
类,它是DataTemplate的x:DataType
。 并且该类不存在这样的属性。
在这里,我可以看到两个选项。 选择其中一个 :
将ViewModel添加为Image类的属性,并将其填充到VM上。
public class Image { (...) public ChapterPageViewModel ViewModel { get; set; } } public class ChapterPageViewModel { (...) private async void Initialize() { pageList = await ComicChapterGet.GetAsync(_chapterId); foreach(Image img in pageList) img.ViewModel = this; } }
只有这一点,以前的代码应该工作,不需要改变任何其他东西。
删除x:绑定并使用ElementName返回到良好的ol’Binding。
这种方式会破坏你的问题的目的,但它确实有效,而且比以前更容易。