x:Bind ViewModel method to an Event inside DataTemplate

本小妞迷上赌 提交于 2019-12-06 15:56:27
Gabriel Rainha

We have two problems here:

First, trying to directly bind an event to a event handler delegate

That will never work, simply put.
One way to handle an event on MVVM pattern is by using EventTrigger and ICommand.
It requires a class that implements ICommand. This post will help you if don't know how to do it. I'll call mine DelegateCommand.

Here's how I would refactor it in two steps:

1) Add a Command to the VM:

public class ChapterPageViewModel
{
    public ChapterPageViewModel()
    {
        this.PageResizedCommand = new DelegateCommand(OnPageResized);
    }

    public DelegateCommand PageResizedCommand { get; }

    private void OnPageResized()
    {  }
}

2) Bind that Command to the SizeChanged event with EventTrigger and InvokeCommandAction.

<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>

"But Gabriel", you say, "that didn't work!"

I know! And that's because of the second problem, which is trying to x:Bind a property that does not belong to the DataTemplate class

This one is closely related to this question, so I´ll borrow some info from there.

From MSDN, regarding DataTemplate and x:Bind

Inside a DataTemplate (whether used as an item template, a content template, or a header template), the value of Path is not interpreted in the context of the page, but in the context of the data object being templated. So that its bindings can be validated (and efficient code generated for them) at compile-time, a DataTemplate needs to declare the type of its data object using x:DataType.

So, when you do <ScrollViewer SizeChanged="{x:Bind ViewModel.PageResized}">, you're actually searching for a property named ViewModel on the that models:Image class, which is the DataTemplate's x:DataType. And such a property does not exist on that class.

Here, I can see two options. Choose one of them:

Add that ViewModel as a property on the Image class, and fill it up on the 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;
    }
}

With only this, that previous code should work with no need to change anything else.

Drop that x:Bind and go back to good ol'Binding with ElementName.

<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>

This one kind of defeat the purpose of your question, but it does work and it's easier to pull off then the previous one.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!