gpt4 book ai didi

c# - 动态用户控件更改 - WPF

转载 作者:太空狗 更新时间:2023-10-30 00:19:51 24 4
gpt4 key购买 nike

我正在 WPF 中开发应用程序,我需要在运行时更改 ContentControl 的内容,具体取决于用户在 ComboBox 上选择的内容。

我有两个 UserControls,在我的组合中有两个 itens,每一个都对应。

第一个用户控件:

<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,下面的 View 模型:

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.xaml.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 检查了应用程序,发现当组合框在内部更改时 View 发生了变化,但 ContentControl 在视觉上仍然是空的。

对于我发布的代码量和我的知识缺失感到抱歉,但我已经处理了很长时间,无法解决这个问题。谢谢

最佳答案

问题:

  • 首先,不要在 ViewModel (UserControl) 中创建与 View 相关的东西。当您这样做时,这不再是 MVVM。
  • ViewModelBase 而不是 ObservableObject 派生 ViewModel,除非您有令人信服的理由在使用 MVVMLight 时不使用 ViewModelBase。为模型保留 ObservableObject 继承。用作 VM 和 M 之间的良好分离
  • 接下来,您不需要像 ObservableCollection<T> 那样将所有内容都设为 _pagesViewModel 。您没有绑定(bind)到 View 中的任何内容,所以这只是一种浪费。只需将其保留为私有(private)列表或数组即可。检查一种类型与其他类似类型的实际区别。
  • 对此不确定,也许您将此代码片段用作演示,但不要使用边距来分隔网格中的项目。您的布局基本上只是 1 个网格单元格,边距的项目不重叠。如果您不知道该问题,请查看 WPF 布局文章。
  • 在编写 UI 应用时,请不要忘记 OOP、封装和排序的原则。当具有 CurrentPageViewModel 之类的属性时,您不希望 View 切换,使属性 setter private 强制执行。
  • 不要过早地在 View 中使用代码隐藏。在这样做之前,首先检查它是否只是与 View 相关的问题。我在谈论你的 ComboBox SelectionChanged 事件处理程序。您在此演示中的目的是切换 VM 中保存的 Bound ViewModel。因此,这不是 View 单独负责的事情。因此寻找涉及 VM 的方法。

解决方案:

您可以从 Here 获取包含上述修复的代码的工作示例,并亲自尝试。

第 1 -> 5 点只是基本的直接更改。

对于 6,我在 MainViewModel 中创建了一个 SelectedVMIndex 属性,该属性绑定(bind)到 SelectedIndexComboBox。因此,当所选索引翻转时,更新自身后的属性 setter 会更新CurrentPageViewModel,例如

public int SelectedVMIndex {
get {
return _selectedVMIndex;
}

set {
if (_selectedVMIndex == value) {
return;
}

_selectedVMIndex = value;
RaisePropertyChanged(() => SelectedVMIndex);

CurrentPageViewModel = _pagesViewModel[_selectedVMIndex];
}
}

关于c# - 动态用户控件更改 - WPF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16244240/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com