2016-11-23 134 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-命令參數) –

相關問題