C# 单个ViewModel的多个视图 问题

C# 单个ViewModel的多个视图 问题,c#,wpf,xaml,mvvm,datatemplate,C#,Wpf,Xaml,Mvvm,Datatemplate,我的WPF窗口中有许多按钮,单击这些按钮时需要更改窗口上的视图,但保持相同的视图模型。昨天我试着使用ControlTemplate来做这个,但是人们提到我最好使用DataTemplate。 我需要通过ViewModel进行绑定,还需要做一些检查,看看用户是否可以访问视图 代码 这是我开始编写的一些代码,但我觉得它不正确 这是我在窗口的视图中定义的数据模板 <DataTemplate x:Key="panel1"> <Grid>

我的
WPF窗口中有许多按钮
,单击这些按钮时需要更改
窗口上的视图
,但保持相同的
视图模型
。昨天我试着使用
ControlTemplate
来做这个,但是人们提到我最好使用
DataTemplate。

我需要通过
ViewModel
进行绑定,还需要做一些检查,看看用户是否可以访问视图

代码
这是我开始编写的一些代码,但我觉得它不正确

这是我在
窗口的视图中定义的
数据模板

    <DataTemplate x:Key="panel1">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="7*"/>
                <ColumnDefinition Width="110*"/>
                <ColumnDefinition Width="190*"/>
                <ColumnDefinition Width="110*"/>
                <ColumnDefinition Width="202*"/>
                <ColumnDefinition Width="109*"/>
                <ColumnDefinition Width="7*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="74*"/>
                <RowDefinition Height="50*"/>
                <RowDefinition Height="12*"/>
                <RowDefinition Height="39*"/>
                <RowDefinition Height="11*"/>
                <RowDefinition Height="38*"/>
                <RowDefinition Height="5*"/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Column="2" Grid.ColumnSpan="3" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Label Content="Video Set:" Foreground="#e37e6e" Grid.Column="2" Grid.ColumnSpan="3" VerticalAlignment="Center" FontSize="22" HorizontalAlignment="Center"/>
                <Image Source="{Binding VideoSet}" Height="25" Width="25" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </StackPanel>

            <TextBlock Foreground="#e37e6e" FontSize="12" Text="You currently do not have a video set. Please click the button below to add a video. Please note you will not be able to create an On Demand presentation without a media file selected. " Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
            <Button Style="{StaticResource loginButton}" Command="{Binding ScreenBack}" Foreground="White" Content="Add Video" Grid.Column="3" HorizontalAlignment="Stretch" Grid.Row="3" VerticalAlignment="Stretch" Grid.ColumnSpan="1"></Button>

        </Grid>
    </DataTemplate>
现在我想通过
ViewModel
将不同的
DataTemplates
绑定到
ContentPresenter
,有人能帮我解决这个问题吗

编辑:

我可以通过静态资源将
ContentPresenter
绑定到
DataTemplate
,如下所示:

<ContentPresenter ContentTemplate="{StaticResource panel1}" Content="{StaticResource panel1}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>
<DataTemplate x:Key="panel1">

</DataTemplate>
但是如何从
ViewModel
更改
ControlPresenter
绑定

编辑:

以下是我的代码周期:

下面是两个数据模板:

<DataTemplate DataType="{x:Type local:ViewModelA}">
     <TextBlock Foreground="#e37e6e" FontSize="12" Text="You currently do not have a video set. Please click the button below to add a video. Please note you will not be able to create an On Demand presentation without a media file selected. " Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelB}">
     <TextBlock Foreground="#e37e6e" FontSize="12" Text="NEWWWWWWWWWWYou" Grid.Row="1" Grid.Column="2" TextWrapping="WrapWithOverflow" TextAlignment="Center" Grid.ColumnSpan="3" />
</DataTemplate>
在WizardViewModel中,我有:

namespace Podia2016.ViewModels
{
    public class WizardViewModel : INotifyPropertyChanged
    {
        public object SelectedViewModel { get; set; }

        ViewModelA s = new ViewModelA();
        ViewModelB d = new ViewModelB();

        public WizardViewModel()
        {
            SelectedViewModel = s;
            OnPropertyChanged("SelectedViewModel"); 

        }

        //BC - BINDS TO CHANGE LECTURE.
        public ICommand Next
        {
            get { return new DelegateCommand<object>(Next_Click); }
        }

        private void Next_Click(object obj)
        {
            SelectedViewModel = d;
            OnPropertyChanged("SelectedViewModel");  
        }
    }

public class ViewModelA : INotifyPropertyChanged
{
    //BC - DEFAULT ONPROPERTYCHANGED EVENT.
    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModelA()
    {

    }

    /// <summary>
    /// This is the standard OnPropertyChanged Event Method 
    /// </summary>
    /// <param name="name"></param>
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

public class ViewModelB : INotifyPropertyChanged
{
    //BC - DEFAULT ONPROPERTYCHANGED EVENT.
    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModelB()
    {

    }

    /// <summary>
    /// This is the standard OnPropertyChanged Event Method 
    /// </summary>
    /// <param name="name"></param>
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}
}
A2016.ViewModels
{
公共类向导ViewModel:INotifyPropertyChanged
{
公共对象SelectedViewModel{get;set;}
ViewModelA s=新的ViewModelA();
ViewModelB d=新的ViewModelB();
公共向导ViewModel()
{
SelectedViewModel=s;
OnPropertyChanged(“SelectedViewModel”);
}
//卑诗省-绑定到改变讲座。
公共i命令下一个
{
获取{返回新的DelegateCommand(单击下一步);}
}
私有无效下一次单击(对象对象对象)
{
SelectedViewModel=d;
OnPropertyChanged(“SelectedViewModel”);
}
}
公共类ViewModelA:INotifyPropertyChanged
{
//BC-默认ONPROPERTYCHANGED事件。
公共事件属性更改事件处理程序属性更改;
公共视图模型a()
{
}
/// 
///这是标准的OnPropertyChanged事件方法
/// 
/// 
受保护的void OnPropertyChanged(字符串名称)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新PropertyChangedEventArgs(名称));
}
}
}
公共类ViewModelB:INotifyPropertyChanged
{
//BC-默认ONPROPERTYCHANGED事件。
公共事件属性更改事件处理程序属性更改;
公共视图模型B()
{
}
/// 
///这是标准的OnPropertyChanged事件方法
/// 
/// 
受保护的void OnPropertyChanged(字符串名称)
{
PropertyChangedEventHandler处理程序=PropertyChanged;
if(处理程序!=null)
{
处理程序(此,新PropertyChangedEventArgs(名称));
}
}
}
}

数据模板
存储为
视图模型
的属性。从
ResourceDictionary
访问数据模板以存储在您的属性中

绑定

如何从代码访问ResourceDictionary:

如果您的WPF项目中有一个用于定义资源的ResourceDictionary,则可以通过以下代码创建它的实例:

ResourceDictionary res = Application.LoadComponent(
 new Uri("/WpfApplication1;component/MyDataTemplateCollection.xaml", 
 UriKind.RelativeOrAbsolute)) as ResourceDictionary;
其中WPFAApplication1是程序集的名称,MyDataTemplateCollection.xaml是ResourceDictionary的名称

另一种方法是为资源字典使用代码隐藏

将x:Class添加到您的ResourceDictionary:

添加class
MyDataTemplateCollection.xaml.cs
作为ResourceDictionary的代码隐藏

代码隐藏类如下所示:

partial class MyDataTemplateCollection: ResourceDictionary
{
   public MyDataTemplateCollection()
   {
      InitializeComponent();
   }     
}
用法:

ResourceDictionary res = new MyDataTemplateCollection();

DataTemplate
存储为
ViewModel
的属性。从
ResourceDictionary
访问数据模板以存储在您的属性中

绑定

如何从代码访问ResourceDictionary:

如果您的WPF项目中有一个用于定义资源的ResourceDictionary,则可以通过以下代码创建它的实例:

ResourceDictionary res = Application.LoadComponent(
 new Uri("/WpfApplication1;component/MyDataTemplateCollection.xaml", 
 UriKind.RelativeOrAbsolute)) as ResourceDictionary;
其中WPFAApplication1是程序集的名称,MyDataTemplateCollection.xaml是ResourceDictionary的名称

另一种方法是为资源字典使用代码隐藏

将x:Class添加到您的ResourceDictionary:

添加class
MyDataTemplateCollection.xaml.cs
作为ResourceDictionary的代码隐藏

代码隐藏类如下所示:

partial class MyDataTemplateCollection: ResourceDictionary
{
   public MyDataTemplateCollection()
   {
      InitializeComponent();
   }     
}
用法:

ResourceDictionary res = new MyDataTemplateCollection();

数据模板的使用要简单得多(与您的尝试相比):

  • 创建子视图模型,每个子视图对应一个模型

  • 定义数据模板


数据模板的使用要简单得多(与您的尝试相比):

  • 创建子视图模型,每个子视图对应一个模型

  • 定义数据模板


你的预期结果是什么,当您试图使用ContentPresenter绑定到DataTemplate时发生了什么?@Tyress我只是在ContentPresenter中收到一条消息,上面写着“System.Windows.Controls.ControlTemplate”,但这不是通过ViewModel实现的,因为我不确定要在其中放入什么。@BenClarke请查看我的answer@BenClarke您如何将ViewModel设置为您的DataContext?@Tyres在代码背后我只是像这样设置DataContext
this.DataContext=\u wizardViewModel您的预期结果是什么,当您试图使用ContentPresenter绑定到DataTemplate时发生了什么?@Tyress我只是在ContentPresenter中收到一条消息,上面写着“System.Windows.Controls.ControlTemplate”,但这不是通过ViewModel实现的,因为我不确定要在其中放入什么。@BenClarke请查看我的answer@BenClarke您如何将ViewModel设置为您的DataContext?@Tyress在c中
// could have base class, may have to implement INotifyPropertyChanged, etc.
public class ViewModelA { }
public class ViewModelB
{
    public string SomeProperty { get; }
}
...

public object SelectedViewModel { get; set; }
<SomeContainer.Resources>
    <!-- using user control -->
    <DataTemplate DataType="{x:Type local:ViewModelA}">
        <local:UserControlA />
    </DataTemplate>
    <!-- or like this -->
    <DataTemplate DataType="{x:Type local:ViewModelB}">
        <Grid>
            <TextBlock Text="{Binding SomeProperty}" />
            <Button .../>
            ...
        </Grid>
    </DataTemplate>
<ContentControl Content="{Binding SelectedViewModel}" />
var a = new ViewModelA();
var b = new ViewModelB() { SomeProperty = "Test" };

// display a - will display UserControlA content in ContentControl
SelectedViewModel = a;
OnPropertyChanged(nameof(SelectedViewModel));

// display b - will display text and button in ContentControl
SelectedViewModel = b;
OnPropertyChanged(nameof(SelectedViewModel));