2014-04-03 85 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。

相关问题