单个 ViewModel 的多个视图
Multiple Views for a single ViewModel
问题
我的 WPF Window
中有许多按钮,单击这些按钮需要更改 Window
上的视图,但保持不变 ViewModel
。昨天我尝试为此使用 ControlTemplate
但有人提到我最好使用 DataTemplate.
我需要通过 ViewModel
进行绑定,并且我需要做一些检查以查看用户是否可以访问该视图。
代码
这是我开始编写的一些代码,但我觉得它不正确。
这是我在 Window.Resources
中定义的 DataTemplate
:
<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>
然后我尝试使用 ContentPresenter
并绑定到 DataTemplate
:
<ContentPresenter Content="{Binding}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>
现在我希望能够通过 ViewModel
将不同的 DataTemplates
绑定到 ContentPresenter
,谁能帮我解决这个问题?
编辑:
我可以通过如下静态资源将 ContentPresenter
绑定到 DataTemplate
:
<ContentPresenter ContentTemplate="{StaticResource panel1}" Content="{StaticResource panel1}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>
DataTemplate
如下所示:
<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>
我的内容控件:
<ContentControl Content="{Binding SelectedViewModel}" />
我在后面的代码中定义了我的 DataContext:
WizardViewModel _wizardViewModel = new WizardViewModel();
this.DataContext = _wizardViewModel;
在我的 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));
}
}
}
}
将 DataTemplate
存储为 ViewModel
的 属性。从 ResourceDictionary
访问 DataTemplate 以存储在您的 属性.
绑定<ContentPresenter Content="{Binding}" ContentTemplate="{Binding template1}" .../>
如何从代码访问 ResourceDictionary:
如果您的 WPF 项目中有一个用于定义资源的 ResourceDictionary,您可以使用如下代码创建它的一个实例:
ResourceDictionary res = Application.LoadComponent(
new Uri("/WpfApplication1;component/MyDataTemplateCollection.xaml",
UriKind.RelativeOrAbsolute)) as ResourceDictionary;
WpfApplication1 是程序集的名称,MyDataTemplateCollection.xaml 是 ResourceDictionary 的名称。
另一种方法是使用资源字典的代码隐藏。
将 x:Class 添加到您的 ResourceDictionary:
添加 class MyDataTemplateCollection.xaml.cs
作为 ResourceDictionary 的代码隐藏。
class 背后的代码如下所示:
partial class MyDataTemplateCollection: ResourceDictionary
{
public MyDataTemplateCollection()
{
InitializeComponent();
}
}
用法:
ResourceDictionary res = new MyDataTemplateCollection();
数据模板使用起来更简单(与您的尝试相比):
- 创建子视图模型,一个对应您想要的每个子视图
// 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>
- 将内容控件绑定到 属性 其中 select 子视图模型
<ContentControl Content="{Binding SelectedViewModel}" />
- 通过更改 selected 子视图模型来控制要显示的内容:
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));
问题
我的 WPF Window
中有许多按钮,单击这些按钮需要更改 Window
上的视图,但保持不变 ViewModel
。昨天我尝试为此使用 ControlTemplate
但有人提到我最好使用 DataTemplate.
我需要通过 ViewModel
进行绑定,并且我需要做一些检查以查看用户是否可以访问该视图。
代码
这是我开始编写的一些代码,但我觉得它不正确。
这是我在 Window.Resources
中定义的 DataTemplate
:
<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>
然后我尝试使用 ContentPresenter
并绑定到 DataTemplate
:
<ContentPresenter Content="{Binding}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>
现在我希望能够通过 ViewModel
将不同的 DataTemplates
绑定到 ContentPresenter
,谁能帮我解决这个问题?
编辑:
我可以通过如下静态资源将 ContentPresenter
绑定到 DataTemplate
:
<ContentPresenter ContentTemplate="{StaticResource panel1}" Content="{StaticResource panel1}" Grid.Row="3" Grid.RowSpan="1" Grid.ColumnSpan="5"/>
DataTemplate
如下所示:
<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>
我的内容控件:
<ContentControl Content="{Binding SelectedViewModel}" />
我在后面的代码中定义了我的 DataContext:
WizardViewModel _wizardViewModel = new WizardViewModel();
this.DataContext = _wizardViewModel;
在我的 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));
}
}
}
}
将 DataTemplate
存储为 ViewModel
的 属性。从 ResourceDictionary
访问 DataTemplate 以存储在您的 属性.
绑定<ContentPresenter Content="{Binding}" ContentTemplate="{Binding template1}" .../>
如何从代码访问 ResourceDictionary:
如果您的 WPF 项目中有一个用于定义资源的 ResourceDictionary,您可以使用如下代码创建它的一个实例:
ResourceDictionary res = Application.LoadComponent(
new Uri("/WpfApplication1;component/MyDataTemplateCollection.xaml",
UriKind.RelativeOrAbsolute)) as ResourceDictionary;
WpfApplication1 是程序集的名称,MyDataTemplateCollection.xaml 是 ResourceDictionary 的名称。
另一种方法是使用资源字典的代码隐藏。
将 x:Class 添加到您的 ResourceDictionary:
添加 class MyDataTemplateCollection.xaml.cs
作为 ResourceDictionary 的代码隐藏。
class 背后的代码如下所示:
partial class MyDataTemplateCollection: ResourceDictionary
{
public MyDataTemplateCollection()
{
InitializeComponent();
}
}
用法:
ResourceDictionary res = new MyDataTemplateCollection();
数据模板使用起来更简单(与您的尝试相比):
- 创建子视图模型,一个对应您想要的每个子视图
// 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>
- 将内容控件绑定到 属性 其中 select 子视图模型
<ContentControl Content="{Binding SelectedViewModel}" />
- 通过更改 selected 子视图模型来控制要显示的内容:
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));