动态用户控制更改- WPF
本文关键字:WPF 用户 控制 动态 | 更新日期: 2023-09-27 18:11:15
我正在开发WPF中的应用程序,我需要在运行时更改ContentControl
的内容,这取决于ComboBox
上选择的用户。
我有两个usercontrol,在我的组合中存在两个条目,每个条目对应一个。
第一个用户控件:
<UserControl x:Class="Validator.RespView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="167" d:DesignWidth="366" Name="Resp">
<Grid>
<CheckBox Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="12,12,0,0" Name="checkBox1" VerticalAlignment="Top" />
<ListBox Height="112" HorizontalAlignment="Left" Margin="12,43,0,0" Name="listBox1" VerticalAlignment="Top" Width="168" />
<Calendar Height="170" HorizontalAlignment="Left" Margin="186,0,0,0" Name="calendar1" VerticalAlignment="Top" Width="180" />
</Grid>
第二个用户控件:
<UserControl x:Class="Validator.DownloadView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="76" d:DesignWidth="354" Name="Download">
<Grid>
<Label Content="States" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" />
<ComboBox Height="23" HorizontalAlignment="Left" Margin="12,35,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" />
<RadioButton Content="Last 48 hs" Height="16" HorizontalAlignment="Left" Margin="230,42,0,0" Name="rdbLast48" VerticalAlignment="Top" />
<Label Content="Kind:" Height="28" HorizontalAlignment="Left" Margin="164,12,0,0" Name="label2" VerticalAlignment="Top" />
<RadioButton Content="General" Height="16" HorizontalAlignment="Left" Margin="165,42,0,0" Name="rdbGeral" VerticalAlignment="Top" />
</Grid>
在MainWindowView.xaml
<Window x:Class="Validator.MainWindowView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:du="clr-namespace:Validator.Download"
xmlns:resp="clr-namespace:Validator.Resp"
Title="Validator" Height="452" Width="668"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize">
<Window.Resources>
<DataTemplate DataType="{x:Type du:DownloadViewModel}">
<du:DownloadView/>
</DataTemplate>
<DataTemplate DataType="{x:Type resp:RespViewModel}">
<resp:RespView/>
</DataTemplate>
</Window.Resources>
<Grid>
<ComboBox ItemsSource="{Binding Path=PagesName}"
SelectedValue="{Binding Path=CurrentPageName}"
HorizontalAlignment="Left" Margin="251,93,0,0"
Name="cmbType"
Width="187" VerticalAlignment="Top" Height="22"
SelectionChanged="cmbType_SelectionChanged_1" />
<ContentControl Content="{Binding CurrentPageViewModel}" Height="171" HorizontalAlignment="Left" Margin="251,121,0,0" Name="contentControl1" VerticalAlignment="Top" Width="383" />
</Grid>
</Window>
我分配给MainView的DataContext
,下面的视图模型:
public class MainWindowViewModel : ObservableObject
{
#region Fields
private ICommand _changePageCommand;
private ViewModelBase _currentPageViewModel;
private ObservableCollection<ViewModelBase> _pagesViewModel = new ObservableCollection<ViewModelBase>();
private readonly ObservableCollection<string> _pagesName = new ObservableCollection<string>();
private string _currentPageName = "";
#endregion
public MainWindowViewModel()
{
this.LoadUserControls();
_pagesName.Add("Download");
_pagesName.Add("Resp");
}
private void LoadUserControls()
{
Type type = this.GetType();
Assembly assembly = type.Assembly;
UserControl reso = (UserControl)assembly.CreateInstance("Validator.RespView");
UserControl download = (UserControl)assembly.CreateInstance("Validator.DownloadView");
_pagesViewModel.Add(new DownloadViewModel());
_pagesViewModel.Add(new RespViewModel());
}
#region Properties / Commands
public ICommand ChangePageCommand
{
get
{
if (_changePageCommand == null)
{
_changePageCommand = new RelayCommand(
p => ChangeViewModel((IPageViewModel)p),
p => p is IPageViewModel);
}
return _changePageCommand;
}
}
public ObservableCollection<string> PagesName
{
get { return _pagesName; }
}
public string CurrentPageName
{
get
{
return _currentPageName;
}
set
{
if (_currentPageName != value)
{
_currentPageName = value;
OnPropertyChanged("CurrentPageName");
}
}
}
public ViewModelBase CurrentPageViewModel
{
get
{
return _currentPageViewModel;
}
set
{
if (_currentPageViewModel != value)
{
_currentPageViewModel = value;
OnPropertyChanged("CurrentPageViewModel");
}
}
}
#endregion
#region Methods
private void ChangeViewModel(IPageViewModel viewModel)
{
int indexCurrentView = _pagesViewModel.IndexOf(CurrentPageViewModel);
indexCurrentView = (indexCurrentView == (_pagesViewModel.Count - 1)) ? 0 : indexCurrentView + 1;
CurrentPageViewModel = _pagesViewModel[indexCurrentView];
}
#endregion
}
在mainwindowview . example .cs中,我编写了这个事件来进行有效的更改:
private void cmbType_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
MainWindowViewModel element = this.DataContext as MainWindowViewModel;
if (element != null)
{
ICommand command = element.ChangePageCommand;
command.Execute(null);
}
}
应用程序运行正常,我用WPFInspector检查了应用程序,发现当组合框内部发生变化时,视图发生了变化,但ContentControl在视觉上仍然是空的。
很抱歉,我发布的代码量和我的知识的缺失,但我与此工作了很长时间,不能解决这个问题。由于
问题:
- 首先不要在ViewModel (
UserControl
)中创建视图相关的东西。当你这样做时,这不再是MVVM。 - 从
ViewModelBase
而不是ObservableObject
派生ViewModels,除非您有令人信服的理由在使用MVVMLight时不使用ViewModelBase
。为模型保留ObservableObject
继承。作为VM和M之间很好的分离 - 下一步,你不需要把所有的
ObservableCollection<T>
像你的_pagesViewModel
。你没有将它绑定到视图中的任何东西,所以这只是浪费。把它保留为私有List或数组。检查一个类型与其他类似类型的实际区别。 - 不确定这个,也许你把这个代码片段作为一个演示,但不要使用边距来分隔网格中的项目。你的布局本质上只是一个网格单元格和页边距有项目不重叠。如果您不知道这个问题,请查看WPF布局文章。
- 在编写UI应用程序时,请不要忘记OOP,封装和排序原则。当你有像
CurrentPageViewModel
这样的属性时,你不打算让视图切换属性设置器private
来强制执行。 - 不要过早地在视图中使用代码隐藏。首先检查是否只是一个视图相关的问题。我在谈论你的
ComboBox
SelectionChanged
事件处理程序。在这个演示中,你的目的是切换绑定视图模型,它保存在VM中。因此这不是视图单独负责的事情。因此,寻找涉及VM的方法。
解决方案/strong>:
你可以从这里获得一个带有上面修复的代码的工作示例,并自己尝试一下。
第1 - 5点只是简单的基本改变。
对于6,我在MainViewModel中创建了一个SelectedVMIndex
属性,该属性绑定到ComboBox
的SelectedIndex
。因此,当所选索引翻转时,属性设置器在更新自身后也会更新CurrentPageViewModel
,例如
public int SelectedVMIndex {
get {
return _selectedVMIndex;
}
set {
if (_selectedVMIndex == value) {
return;
}
_selectedVMIndex = value;
RaisePropertyChanged(() => SelectedVMIndex);
CurrentPageViewModel = _pagesViewModel[_selectedVMIndex];
}
}