2016-11-23 133 views
1

我基本上提出了与this person相同的问题,但在更新的x:Bind的上下文中。x:将ViewModel方法绑定到DataTemplate中的事件

的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; } 
} 

而在ChapterPageViewModel

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 
} 
+0

那个模型:Image类有一个ViewModel属性吗?如果不是,并且您试图引用与“FlipView.ItemsSource”绑定的相同ViewModel,那么您将无法以这种方式访问​​它,因为DataTemplate的DataContext现在是模型:Image目的。 –

+0

它的确如此。如果我取出SizeChanged =“{x:Bind ViewModel.PageResized}”,代码将起作用。但我需要能够调整ScrollView大小的图像大小,这需要我从模板中访问ViewModel属性。 – rancor1223

+0

你介意添加该Image类的代码吗? –

回答

2

我们这里有两个问题:

首先,试图将事件直接绑定到事件处理程序委托

那将永远不会工作,简单地说。
处理MVVM模式事件的一种方法是使用EventTrigger and ICommand.
它需要一个实现ICommand的类。 This post会帮助你,如果不知道如何去做。我会打电话给我的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> 

“但加布里埃尔”,你说,“没有工作!”

我知道!那是因为第二个问题,这是试图x的:绑定不属于的DataTemplate类

这一个密切相关this question,所以I'll从那里借一些信息的属性。

从MSDN,关于DataTemplate and x:Bind

里面一个DataTemplate(是否用作项目模板,内容 模板,或报头模板),Path的值未在的上下文中解释 页面,但是在模板化的数据对象 的上下文中。为了使其绑定可以在编译时验证(并且为其生成的代码有效),DataTemplate需要使用x:DataType来声明其数据对象的类型。

所以,当你做<ScrollViewer SizeChanged="{x:Bind ViewModel.PageResized}">,你实际上是寻找一个在那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良好的绑定。

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

这一种的失败你的问题的目的,但它确实工作,它更容易拉断,然后前一个。

+0

这个技巧。并介绍了其他问题 - 无法获取事件参数。但是,这让我意识到,只要阅读模板儿童的尺寸,我就可以让自己的生活更加艰难,因为我可以更好地(更容易地)阅读FlipView尺寸。而且这个Command例子在将来肯定会有用。谢谢! – rancor1223

+0

@ rancor1223那么,事件参数是MVVM的一个老问题。所以,[我会在这里留下](http:// stackoverflow。COM /问题/ 6205472/MVVM传递-EventArgs的-AS-命令参数) –

相关问题