2013-08-29 62 views
6

首先要做的事情是,先設置一些上下文。如果您熟悉問題,請跳至BindingExpression部分。這是我在WPF中的第一個主要項目,所以我對MVVM模式仍然很陌生。 Here是我發現的唯一另外一個類似的問題,它的低調答案並沒有真正引起我很大的興趣。在MVVM應用程序中切換ViewModels時發生BindingExpression路徑錯誤

我有/建立一個.NET 3.5 WPF應用程序,我使用MVVM(自己實現,沒有框架)。在此範圍內,我有一些ViewsViewModels。這些分別位於主人ApplicationViewApplicationViewModel之內。

我更改視圖的方式是通過使用XAML的DataTemplate元件在ApplicationView,像這樣:

<DataTemplate DataType="{x:Type viewmodels:InitViewModel}"> 
    <views:InitView /> 
</DataTemplate> 

然後在主體我有結合於場所在ApplicationViewModel

<ContentControl Content="{Binding CurrentPageViewModel}"/> 
一個ContentControl中

當我運行該應用程序時,所有這些似乎工作正常,並且完全按照預期操作。但是,當我在運行後查看調試輸出時,出現很多BindingExpression錯誤。

這裏是一個例子。我有一個物業,SplashText,在我的InitViewModel。這被綁定到閃屏中的文本塊(InitView)。當啓動畫面結束,我轉出的視圖模型,我得到如下:

System.Windows.Data Error: 39 : BindingExpression path error: 'SplashText' property not found on 'object' ''MainMenuViewModel' (HashCode=680171)'. BindingExpression:Path=SplashText; DataItem='MainMenuViewModel' (HashCode=680171); target element is 'TextBox' (Name='FeedBackBox'); target property is 'Text' (type 'String')

我明白,這是因爲綁定仍然存在,但在DataContext的CurrentPageViewModel屬性已更改。所以我想知道的是:

  • 這是一個稍縱即逝的問題,即當不使用視圖時,或者它們(和壞的綁定)在內存中無限期地放置嗎?
  • 有沒有一種方法可以在視圖處於非活動狀態時清理或取消激活這些綁定?
  • 如果我單獨留下這些,會對我的應用程序造成怎樣的性能下降?
  • 有沒有更好的方法來切換視圖,避免這個問題?

在此先感謝,併爲單片問題道歉。

編輯03/09/13 - 感謝Jehof,Francesco De Lisi和Faster Solutions,指出將子視圖datacontext設置爲{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}是沒有意義的,因爲ContentControl負責處理datacontext。

回答

1

看起來你的DataContext轉到MainMenuViewModel,而你的財產屬於另一個ViewModel產生錯誤。

CurrentPageViewModel值前後閃屏切換失敗Binding切換視圖。

問題是dued到DataContext="{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"

事實上,CurrentPageViewModel = InitViewModel當你的應用程序啓動,但問題是,每View具有相同DataContext(最初即InitViewModel),但我敢肯定,ViewModels沒有整個需要的屬性池滿足視圖綁定。 要了解的示例:

ViewXPropertyX具有約束力,在ViewModelX中進行管理。 ViewYPropertyY具有約束力,在ViewModelY中進行管理。 兩者都有DataContext = CurrentViewModel

在啓動CurrentViewModel = ViewModelX和ViewX和ViewY都有DataContext = ViewModelX。但是這是錯了!可能會產生一個錯誤。

我通常會做的是在View類中設置DataContext(如果您願意,可以使用cs或XAML),並使用相應的View Model來確保它合適。然後,在需要時,每次切換頁面時我都會調用刷新方法來更新我的值。如果您有共享屬性,請考慮使用模型集中您的信息(和值)。

樣本圖像從http://wildermuth.com/images/mvvm_layout.png

enter image description here

顯然的意見是由你的主窗口包裹的控件。

希望它很清楚。

+0

那麼你所建議的是直接將datacontext硬編碼到每個視圖中,而不是綁定到主視圖模型中的currentViewModel屬性?對我來說,這似乎有點混亂。然而,我認爲這個答案可能是迄今爲止實際提供解決方案中最接近的3個答案。 –

+0

1:1綁定是最簡單的解決方案。查看http://msdn.microsoft.com/en-us/library/gg405494(v=pandp.40).aspx高級MVVM模式。 –

+0

by 1:1 binding,你是說Mode = OneTime? –

0

讓我們回答您的問題順序:

  1. 你或許已經知道這個問題的答案。當.NET垃圾收集時,它會從堆中移除你的View對象。但是直到這個時候,你的View對象仍然綁定到頁面上的主DataContext,並且會對DataContext已更改的事件作出反應。
  2. 顯而易見的事情是將Views DataContext設置爲null。 DataContext是一個依賴項屬性,因此空值範圍將只是您的View。
  3. 正如其他/暗淡的答案所說,它會減慢你一點,但不是很多。我不會太擔心這件事。
  4. 是的。這裏有一個有用的線程查看導航選項:View Navigation Options

我也建議看一個框架。像MVVM Light這樣重量輕的產品可以很少爲您解決一系列問題。它的ViewModelLocator模式也可以做你正在做的,但沒有副作用,並提供了一大堆的清理選項。

+0

但是當視圖不再在範圍內時,將datacontext設置爲null停止bindingexpression路徑錯誤?你將如何決定何時取消datacontext,在usercontrol的特定事件? –

+0

我認爲會的。你看,DataContext是一個依賴屬性。因爲它是一個依賴屬性,它會做幾件事情:它會通知綁定的變化,並且它會保存一個值的層次結構。通過擁有自己的價值,它將不再取決於它從Page/User Control/Window中繼承的價值。至於決定何時取消上下文,這取決於您的應用程序結構。一種選擇是監視你的子View上的DataContextChanged事件。這會告訴你什麼時候DataContext發生了變化,然後你可以對該事件做出反應。 –

+0

這一切都很好,並且會修復從'InitView'到'MainMenuView'的過渡,因爲我們不必重新訪問啓動畫面。但是,例如,當我切換到主菜單的工作流視圖模型,然後返回到主菜單時,就會出現問題。它的datacontext將是空的,我需要找到一種方法來重置它,或者只是接受綁定表達式的錯誤。 –

0

可以省略的DataContext的結合在你的瀏覽

DataContext="{Binding DataContext.CurrentPageViewModel, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" 

原因您ViewDataContextContentControlDataContext和得到你的Content,物業結合設置。

所以,當你的財產CurrentPageViewModel設置爲InitViewModelContentControl將使用InitViewModelDataContext,並使用InitViewContentTemplate,它會設置自己的DataContext作爲InitView的DataContext的。

+0

有用,謝謝,但不解決bindingexpression路徑錯誤 –

1

您的具體示例在.NET 4.5中不可重現,這可能意味着Microsoft已經解決了此問題。

儘管如此,當Content和ContentTemplate都是數據綁定時,存在類似的問題。我將解決這個問題,如果有人仍在使用它,那麼這也可能解決.NET 3.5中的問題。例如:

<ContentControl Content="{Binding Content}" ContentTemplate="{Binding Template}" /> 

或者當的ContentTemplate由DataTrigger確定:

<ContentControl Content="{Binding Content}"> 
    <ContentControl.Style> 
     <Style TargetType="{x:Type ContentControl}"> 
      <Style.Triggers> 
       <DataTrigger Binding="{Binding Choice}" Value="1"> 
        <Setter Property="ContentTemplate" Value="{StaticResource TemplateA}" /> 
       </DataTrigger> 
       <DataTrigger Binding="{Binding Choice}" Value="2"> 
        <Setter Property="ContentTemplate" Value="{StaticResource TemplateB}" /> 
       </DataTrigger> 
      </Style.Triggers> 
     </Style> 
    </ContentControl.Style> 
</ContentControl> 

在兩種情況下,可以得到類似的觀察到的那些OP綁定錯誤。

這裏的竅門是確保Content和ContentTemplate的更改以正確的順序執行以防止綁定錯誤。我寫了DelayedContentControl,它確保Content和ContentTemplate同時按照正確的順序進行更改。

<jc:DelayedContentControl Content="{Binding Content}" ContentTemplate="{Binding Template}"> 

對於DataTrigger情況也是類似的。

您可以從我的開源JungleControls library獲得DelayedContentControl。

相關問題