动态用户控制的变化 - WPF [英] Dynamic user control change - WPF

查看:129
本文介绍了动态用户控制的变化 - WPF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发展在WPF应用程序,我需要在运行时更改的内容 ContentControl中根据比选择的用户组合框

I'm developing an app in WPF and I need to change in runtime a content of a ContentControl depending than the user selected on ComboBox.

我有两个用户控件,并在我的组合存在2 itens,相应的每各一个。

I have two UserControls and at my combo exists two itens, corresponding each one each.

首先用户控件:

<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

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



我分配到的DataContext 中的MainView的,下面的视图模型:

I assigned to the DataContext of the MainView, the viewmodel below:

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,我写了这个事件做了有效的改变:

On MainWindowView.xaml.cs, I wrote this event to do the effective change:

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中视觉空..

The app run ok and I inspected the application with WPFInspector and saw that the view changes when the combobox is changed internally, but the ContentControl still empty visually..

抱歉的代码,我张贴的数量和我的知识的思念但我有这方面的工作很长一段时间并不能解决这个问题。
谢谢

Sorry about the amount of code that I posted and my miss of knowledge but I'm working with this a long time and can't solve this problem. Thanks

推荐答案

问题:


  • 首先不要曾经创造查看相关的视图模型的东西(用户控件)。这不再是MVVM当你这样做。

  • 派生的ViewModels从 ViewModelBase ,而不是 ObservableObject ,除非你有一个令人信服的理由不使用 ViewModelBase 使用MVVMLight时。为保持模型 ObservableObject 的传承。作为虚拟机和M的之间一个很好的分离

  • 接下来,你不需要让一切的的ObservableCollection< T> 喜欢你的 _pagesViewModel 。你不必是绑定到任何您查看的所以它只是一种浪费。只要保持作为一个私有列表或数组。检查什么类型的实际差异确实给了类似的另一种。

  • 不知道这一个,也许你拉到这个代码片断作为演示,但不要用利润率将在单独项目一个网格。你的布局本质上只是1网格单元和利润率的项目不重叠。如果你不知道这个问题的,检查到WPF布局文章。

  • 请不要写UI应用程序的时候忘了OOP,封装和排序的原则。有像 CurrentPageViewModel 属性,你不打算视图切换使得当属性setter 私人来强制执行。

  • 请不要再打代码隐藏在View太快。首先检查它是否查看相关才这样做的问题。我谈论你的组合框 的SelectionChanged 事件处理程序。你对在这个演示的目的是开关,它是在VM举行的绑定视图模型。因此,它不是该视图是全权负责。因此,寻找一个VM参与办法

  • Firstly don't ever create View related stuff in the ViewModel (UserControl). This is no longer MVVM when you do that.
  • Derive ViewModels from ViewModelBase and not ObservableObject unless you have a compelling reason to not use ViewModelBase when using MVVMLight. Keep ObservableObject inheritence for Models. Serves as a nice separation between VM's and M's
  • Next you do not need to make everything an ObservableCollection<T> like your _pagesViewModel. You do not have that bound to anything in your View's so it's just a waste. Just keep that as a private List or array. Check what a type actually does in difference to a similar other one.
  • Not sure about this one, maybe you pulled this code snippet as a demo, but do not use margins to separate items in a Grid. Your Layout is essentially just 1 Grid cell and the margins have the items not overlap. If you're not aware of that issue, Check into WPF Layout Articles.
  • Please don't forget principles of OOP, Encapsulation and sorts when writing a UI app. When having Properties like CurrentPageViewModel which you don't intend the View to switch make the property setter private to enforce that.
  • Don't resort to code-behind in the View too soon. Firstly check if it's only a View related concern before doing so. Am talking about your ComboBox SelectionChanged event handler. Your purpose of that in this demo is to switch the Bound ViewModel which is held in the VM. Hence it's not something that the View is solely responsible for. Thus look for a VM involved approach.

解决方案

您可以从在这里 并尝试一下自己

You can get a working example of your code with the fixes for above from Here and try it out yourself.

1点 - > 5只是简单的基本变化。

Points 1 -> 5 are just basic straightforward changes.

有关6中,我创建了绑定到<$ C $在MainViewModel一个 SelectedVMIndex 属性C>的SelectedIndex 组合框的> 。因此,当所选的指数翻转,更新自己,后属性setter更新 CurrentPageViewModel 以及诸如

For 6, I've created a SelectedVMIndex property in the MainViewModel which is bound to the SelectedIndex of the ComboBox. Thus when the selected index flips, the property setter after updating itself updates the CurrentPageViewModel as well such as

public int SelectedVMIndex {
  get {
    return _selectedVMIndex;
  }

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

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

    CurrentPageViewModel = _pagesViewModel[_selectedVMIndex];
  }
}

这篇关于动态用户控制的变化 - WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆