2014-04-03 116 views
0

我在Windows Phone 8應用程序中使用MVVM。我想從我的外殼視圖模型中的1視圖模型移動到另一個視圖模型。我似乎無法讓ContentControl綁定到視圖模型上的usercontrol/phoneApplicationPage模板。將ContentControl綁定到ViewModel的視圖

我錯過了什麼?

我試圖避免像MVVM光的事情。 (我希望我的應用盡可能小一點下載),這應該是可以做到的。

P.S.我仍然很新的WPF/WP8

這裏是我到目前爲止的樣本,請原諒啞功能:)

/**殼牌視圖**/

<phone:PhoneApplicationPage 
    x:Class="PhoneAppWithDataContext.Navigation.ViewModelNavigation" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    FontFamily="{StaticResource PhoneFontFamilyNormal}" 
    FontSize="{StaticResource PhoneFontSizeNormal}" 
    Foreground="{StaticResource PhoneForegroundBrush}" 
    SupportedOrientations="Portrait" Orientation="Portrait" 
    mc:Ignorable="d" 
    shell:SystemTray.IsVisible="True" 
    xmlns:vm="clr-namespace:PhoneAppWithDataContext.Navigation"> 

    <phone:PhoneApplicationPage.DataContext> 
     <vm:AppViewModel/> 
    </phone:PhoneApplicationPage.DataContext> 
    <phone:PhoneApplicationPage.Resources> 
     <DataTemplate x:Key="MonthViewModel"> 
      <vm:MonthViewControl/> 
     </DataTemplate> 
    </phone:PhoneApplicationPage.Resources> 

    <!--LayoutRoot is the root grid where all page content is placed--> 
    <Grid x:Name="LayoutRoot" Background="Transparent"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 

     <!--TitlePanel contains the name of the application and page title--> 
     <StackPanel Grid.Row="0" Margin="12,17,0,28"> 
      <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/> 
      <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 
     </StackPanel> 

     <!--ContentPanel - place additional content here--> 
     <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 
      <ContentControl Content="{Binding CurrentViewModel}" 
       ContentTemplate="{Binding ContentTemplate}" 
       HorizontalContentAlignment="Stretch" 
       VerticalContentAlignment="Stretch"/> 
     </Grid> 
     <Button Content="Change VM" Command="{Binding ChangeViewModelCommand}"/> 
    </Grid> 
</phone:PhoneApplicationPage> 

/**殼/應用程序視圖模型**/

public class AppViewModel : ViewModelBase 
{ 
    private ViewModelBase _currentViewModel; 
    private List<ViewModelBase> _viewModels = new List<ViewModelBase>(); 
    private byte _month = 1; 

    public ViewModelBase CurrentViewModel 
    { 
     get 
     { 
      return _currentViewModel; 
     } 
     set 
     { 
      if (_currentViewModel == value) 
       return; 

      _currentViewModel = value; 
      NotifyPropertyChanged("CurrentViewModel"); 
     } 
    } 

    public DataTemplate SelectedTemplate 
    { 
     get 
     { 
      if (_currentViewModel == null) 
       return null; 
      return DataTemplateSelector.GetTemplate(_currentViewModel); 
     } 
    } 

    public List<ViewModelBase> ViewModels 
    { 
     get 
     { 
      return _viewModels; 
     } 
    } 

    public AppViewModel() 
    { 
     ViewModels.Add(new MonthViewModel(_month)); 
     CurrentViewModel = ViewModels.FirstOrDefault(); 
    } 

    private ICommand _changeViewModelCommand; 
    public ICommand ChangeViewModelCommand 
    { 
     get 
     { 
      return _changeViewModelCommand ?? (_changeViewModelCommand = new GenericCommand(() => 
      { 
       _month++; 
       var newVM = new MonthViewModel(_month); 
       ViewModels.Add(newVM); 
       CurrentViewModel = newVM; 

      }, true)); 
     } 
    } 
    private void ChangeViewModel(ViewModelBase viewModel) 
    { 
     if (!ViewModels.Contains(viewModel)) 
      ViewModels.Add(viewModel); 

     CurrentViewModel = ViewModels.FirstOrDefault(vm => vm == viewModel); 
    } 
} 

/** ** DataTemplateSelector/

public static class DataTemplateSelector 
{ 
    public static DataTemplate GetTemplate(ViewModelBase param) 
    { 
     Type t = param.GetType(); 
     return App.Current.Resources[t.Name] as DataTemplate; 
    } 
} 

/**用戶控制**/

<UserControl x:Class="PhoneAppWithDataContext.Navigation.MonthViewControl" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" 
    FontFamily="{StaticResource PhoneFontFamilyNormal}" 
    FontSize="{StaticResource PhoneFontSizeNormal}" 
    Foreground="{StaticResource PhoneForegroundBrush}" 
    d:DesignHeight="480" d:DesignWidth="480" 
    xmlns:vm="clr-namespace:PhoneAppWithDataContext.Navigation"> 


    <UserControl.DataContext> 
     <vm:MonthViewModel/> 
    </UserControl.DataContext> 

    <Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}"> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto"/> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="100"/> 
      <ColumnDefinition Width="Auto"/> 
     </Grid.ColumnDefinitions> 
     <TextBlock Text="Id" Width="100" VerticalAlignment="Center" Grid.Row="0" Grid.Column="0" /> 
     <TextBlock Text="{Binding Id}" Width="100" VerticalAlignment="Center" Grid.Row="0" Grid.Column="1" /> 
     <TextBlock Text="Name" Width="100" VerticalAlignment="Center" Grid.Row="1" Grid.Column="0" /> 
     <TextBlock Text="{Binding Name}" Width="100" VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" /> 
    </Grid> 
</UserControl> 

/** ** ViewModelBase/

public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void NotifyPropertyChanged(String propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

/**查看用戶控件應該綁定的模型**/

public sealed class MonthViewModel : ViewModelBase 
{ 
    private byte _id; 
    private string _name; 

    public MonthViewModel() 
    { 
    } 

    public MonthViewModel(byte id) 
    { 
     _id = id; 
     _name = "Month " + id.ToString() + " of the year"; 
    } 

    public override string ToString() 
    { 
     return _name; 
    } 

    public byte Id 
    { 
     get 
     { 
      return _id; 
     } 
    } 
    public string Name 
    { 
     get 
     { 
      return _name; 
     } 
    } 
} 
+0

我已經從問題標題中刪除了一個標記 - 請注意比大多數情況下的問題[不應在標題中包含標記](http://meta.stackexchange.com/questions/19190/should-questions-include標籤都有效 - 在 - 他們 - 標題)。 – Romasz

+0

你正在將你的「Content」屬性綁定到一個顯然不能從FrameworkElement繼承的「ViewModel」對象。您需要綁定到從中派生出來的東西,或理想情況下的UserControl。 – BradleyDotNET

+0

@LordTakkera我相信這是錯誤的。我把我的ContentControl綁定到一個視圖模型,它工作的很棒:) – Kcvin

回答

1

我相信這裏的問題是:

<UserControl.DataContext> 
    <vm:MonthViewModel/> 
</UserControl.DataContext> 

當你的Content從一個MonthViewModel改爲了下,返回的DataTemplate的DataContext設置綁定到Content的對象。那麼,一旦設置了DataContext,你應該很好走,但是一旦UserControl被加載,它將DataContext重置爲一個空的MonthViewModel的新實例(vm:MonthViewModel)。擺脫顯式的DataContext聲明 - 換句話說,刪除我上面發佈的代碼。

這樣,當您第一次調用CurrentViewModel並引發INPC時,它不會重置DataContext。當你在MonthViewModel類型的CurrentViewModel之間切換時,你的UserControl不會再次調用InitializeComponent,相反,DataContext會改變。

編輯

另外,如果你還沒有看到變化,那麼我會指向SelectedTemplate財產。而不是在屬性中的空檢查,只需將null傳遞給GetTemplate。在GetTemplate的內部,檢查是否爲null,如果爲null,則返回null。

相關問題