【问题标题】:Binding ContentControl to a View for a ViewModel将 ContentControl 绑定到 ViewModel 的视图
【发布时间】:2014-04-03 20:04:41
【问题描述】:

我在 windows phone 8 应用程序中使用 MVVM。我想在我的 shell 视图模型中从一个视图模型移动到另一个视图模型。我似乎无法让 ContentControl 绑定到作为视图模型上的 usercontrol/phoneApplicationPage 的模板。

我错过了什么?

我试图避免像 MVVM 灯这样的事情。 (我希望我的应用程序的下载量尽可能小)这应该是可以做到的。

附:我对 WPF/WP8 还是很陌生

这是我到目前为止的一个示例,请原谅愚蠢的功能:)

/** Shell 视图 **/

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

/** Shell/应用程序视图模型**/

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

/** 数据模板选择器 **/

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

【问题讨论】:

  • 我已经从问题标题中删除了一个标签 - 请注意大多数情况下的问题shouldn't include tag in their title
  • 您正在将您的“内容”属性绑定到一个显然不是从 FrameworkElement 继承的“视图模型”对象。您需要绑定到派生自 UserControl 的东西,或者理想情况下是 UserControl。
  • @LordTakkera 我认为这是错误的。我将我的 ContentControl 绑定到一个视图模型,它工作得很好:)

标签: c# wpf windows-phone-8 mvvm


【解决方案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 属性。而不是属性中的空检查,只需将空传递给GetTemplate。在GetTemplate 内部,检查是否为null,如果为null,则返回null。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-03
    • 2011-01-31
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多