我基本上问了与这个人相同的问题,但在较新的x:Bind
中。
ViewModels的DataContext定义如
<Page.DataContext>
<vm:ChapterPageViewModel x:Name="ViewModel" />
</Page.DataContext>
因此,每当我需要绑定某件事时,我都会明确地将其做到
ItemsSource="{x:Bind ViewModel.pageList, Mode=OneWay}"
但是,在模板中不起作用
<FlipView ItemsSource="{x:Bind ViewModel.pageList, Mode=OneWay}">
<FlipView.ItemTemplate>
<DataTemplate x:DataType="models:Image">
<ScrollViewer SizeChanged="{x:Bind ViewModel.PageResized}"> <-- this here is the culprit
<Image Source="{x:Bind url}"/>
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
阅读文档,我发现使用Path
基本上应该将上下文重置到页面上,但是(x:Bind Path=ViewModel.PageResizeEvent
也没有起作用。我仍然得到Object reference not set to an instance of an object
,这应该意味着它看不到方法(但是一个空)。
图像类:
public class Image {
public int page { get; set; }
public string url { get; set; }
public int width { get; set; }
public int heigth { get; set; }
}
和章节pageViewModel
private List<Image> _pageList;
public List<Image> pageList {
get { return _pageList; }
set { Set(ref _pageList, value); }
}
public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode,
IDictionary<string, object> 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事件。
<Page (...)
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core">
(...)
<FlipView ItemsSource="{x:Bind ViewModel.pageList, Mode=OneWay}" >
<FlipView.ItemTemplate>
<DataTemplate x:DataType="models:Image">
<ScrollViewer>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SizeChanged">
<core:InvokeCommandAction
Command="{x:Bind ViewModel.PageResizedCommand }" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Image Source="{x:Bind url}"/>
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
</Page>
"但是Gabriel" ,您说,"那不起作用!"
我知道!这是因为第二个问题,即尝试x:绑定不属于datateMplate类的属性
这个问题与此问题密切相关,因此我将从那里借一些信息。
来自MSDN,关于DataTemplate和X:bind
在数据板板内(是否用作项目模板,内容 模板或标题模板),未解释路径的值 在页面的上下文中,但在数据对象的上下文中 被模板。以便可以验证其绑定(有效 为它们生成的代码)在编译时,数据板需要 使用x:datatype。
声明其数据对象的类型
因此,当您进行<ScrollViewer SizeChanged="{x:Bind ViewModel.PageResized}">
时,实际上您正在搜索该 models:Image
类中名为ViewModel的属性,即DatateMplate的x:DataType
。在该类别上不存在这样的属性。
在这里,我可以看到两个选项。选择其中一个:
添加该ViewModel作为图像类上的属性,然后将其填充在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:绑定并返回元素名称。
<FlipView ItemsSource="{x:Bind ViewModel.pageList, Mode=OneWay}" x:Name="flipView">
<FlipView.ItemTemplate>
<DataTemplate x:DataType="models:Image">
<ScrollViewer>
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SizeChanged">
<core:InvokeCommandAction
Command="{Binding DataContext.PageResizedCommand
, ElementName=flipView}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Image Source="{x:Bind url}"/>
</ScrollViewer>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
这是一种击败您的问题的目的,但它确实有效,并且更容易实现。