4

私は WPF でアプリを開発しています。実行時にContentControl、ユーザーが選択したものよりも依存するコンテンツを変更する必要がありますComboBox

私は 2 つの UserControls を持っており、私のコンボには 2 つの 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>

2 番目のユーザー コントロール:

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

DataContext以下のビューモデルである MainViewに割り当てました。

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 を使用してアプリケーションを調べたところ、コンボボックスが内部で変更されるとビューが変更されることがわかりましたが、ContentControl はまだ視覚的に空です..

投稿したコードの量と知識の欠如について申し訳ありませんが、これに長い間取り組んでいるため、この問題を解決できません。ありがとう

4

1 に答える 1

10

問題:

  • まず、ViewModel ( ) で View 関連のものを作成しないUserControlでください。これを行うと、これはもはや MVVM ではありません。
  • MVVMLight を使用するときに使用しないやむを得ない理由がViewModelBaseない限り、 ViewModel を派生させます。モデルの継承を保持します。VM と M の間の適切な分離として機能します。ObservableObjectViewModelBaseObservableObject
  • ObservableCollection<T>次に、すべてを のようにする必要はありません_pagesViewModel。ビューの何にもバインドされていないので、無駄です。それをプライベートなリストまたは配列として保持してください。類似の他のタイプとの違いで、タイプが実際に何をするかを確認してください。
  • これについてはよくわかりません。このコード スニペットをデモとしてプルしたのかもしれませんが、グリッド内のアイテムを区切るために余白を使用しないでください。レイアウトは基本的に 1 つのグリッド セルであり、余白にはアイテムが重なっていません。その問題を認識していない場合は、WPF レイアウトの記事を確認してください。
  • UI アプリを作成するときは、OOP、カプセル化、並べ替えの原則を忘れないでください。CurrentPageViewModelビューを切り替えるつもりのないようなプロパティがある場合は、それprivateを強制するようにプロパティ セッターを作成します。
  • すぐにビューでコード ビハインドに頼らないでください。そうする前に、まずそれがビュー関連の問題だけであるかどうかを確認してください。ComboBox SelectionChangedイベントハンドラについて話しています。このデモでの目的は、VM に保持されている Bound ViewModel を切り替えることです。したがって、ビューが単独で責任を負うものではありません。したがって、VM が関与するアプローチを探します。

解決策:

ここから上記の修正を加えたコードの実際の例を入手して、自分で試してみることができます。

ポイント 1 -> 5 は基本的な簡単な変更です。

6 の場合SelectedVMIndex、MainViewModel にプロパティを作成しましSelectedIndexComboBox。したがって、選択されたインデックスが反転すると、プロパティ セッターは自身を更新した後、次のように更新しますCurrentPageViewModel

public int SelectedVMIndex {
  get {
    return _selectedVMIndex;
  }

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

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

    CurrentPageViewModel = _pagesViewModel[_selectedVMIndex];
  }
}
于 2013-04-27T07:38:28.360 に答える