Как я могу передать этот параметр ViewModel при отображении TreeView? - PullRequest
0 голосов
/ 25 октября 2019

Когда я передаю параметр в MainViewModel, содержимое TreeView не отображается.

Я новичок в C # и MVVM. Когда я создал MainViewModel и TreeView, они работали нормально. Затем, теперь я хотел бы выбрать определенные тестовые элементы из всего списка и показать только те TreeView. Отборочная часть была сделана независимо, и сейчас я пытаюсь объединить их. Однако, когда я передаю выбранный список тестов в MainViewModel, TreeView перестает показывать содержимое. Если я не передам параметр, содержимое появится снова.

Я также добавил простой TreeView без каких-либо привязок, все написано на XAML. Содержимое отображается независимо от того, передан ли параметр или нет. Итак, я думаю, что это не проблема TreeView, а проблема привязки.

Вот мои полные коды:

ViewModels / MainViewModel.cs

using TwoListBoxes.Models;
using System.Collections.ObjectModel;
using System.Collections.Generic;

namespace TwoListBoxes.ViewModels
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel() 
        {
        } // <= To show the contents, comment these lines out

        public MainViewModel(List<string> selectedTestList) // <= To show the contents, comment these lines out
        { // <= To show the contents, comment these lines out

            // ### I'd like to use selectedTestList as a search key here ###

            var TotalModel = new TotalModel(
                        failNum: 123,
                        failRate: 45.6
                );
            var TotalViewModel = new TotalViewModel(TotalModel);
            TotalViewModel.AddTotal(TotalModel);
            Totals.Add(TotalViewModel);
        }

        public ObservableCollection<TotalViewModel> Totals { get; } 
            = new ObservableCollection<TotalViewModel>();
    }
}

ViewModels / TotalViewModel.cs

using TwoListBoxes.Models;
using System.Collections.ObjectModel;

namespace TwoListBoxes.ViewModels
{
    public class TotalViewModel : ViewModelBase<TotalModel>
    {
        public TotalViewModel(TotalModel model) : base(model)
        {
        }

        public ObservableCollection<TotalViewModel> Totals { get; } 
            = new ObservableCollection<TotalViewModel>();

        public void AddTotal(TotalModel total)
        {
            var viewModel = new TotalViewModel(total);
            Totals.Add(viewModel);
        }

        public string TotalName => $"{Model.FailNum} {Model.FailRate}";
    }
}

ViewModels / ViewModelBase.cs

using System.ComponentModel;
using System.Runtime.CompilerServices;

using JetBrains.Annotations;

namespace TwoListBoxes.ViewModels
{
    public abstract class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public abstract class ViewModelBase<TModel> : ViewModelBase
        where TModel : class
    {
        private TModel _model;

        public ViewModelBase(TModel model)
            => _model = model;

         public TModel Model
        {
            get => _model;
            set
            {
                if (ReferenceEquals(_model, value))
                {
                    return;
                }

                _model = value;
                OnPropertyChanged();
            }
        }
    }
}

Models / TotalModel.cs

namespace TwoListBoxes.Models
{
    public class TotalModel
    {
        public TotalModel(
           int failNum,
           double failRate
        )
        {
            FailNum = failNum;
            FailRate = failRate;
        }

        public int FailNum { get; }
        public double FailRate { get; }
    }
}

Views / CalcWindow.xaml.cs

using TwoListBoxes.ViewModels;
using System.Collections.Generic;
using System.Windows;

namespace TwoListBoxes.Views
{
    public partial class CalcWindow : Window
    {
        public CalcWindow()
        {
            InitializeComponent();
        }

        public CalcWindow(List<string> selectedTestList) : this()
        {
            // shows the TreeView
            //new MainViewModel();

            // does NOT show the TreeView
            new MainViewModel(selectedTestList);
        }
    }
}

Views / CalcWindow.xaml

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:viewModels="clr-namespace:TwoListBoxes.ViewModels"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="TwoListBoxes.Views.CalcWindow"
    Title="TreeView" Width="1000" Height="512">
<Window.DataContext>
    <viewModels:MainViewModel/>
</Window.DataContext>

<Window.Resources>
    <CollectionViewSource x:Key="ViewSource1" Source="{Binding Partials}"/>
    <CollectionViewSource x:Key="ViewSource2" Source="{Binding Totals}"/>
    <CompositeCollection x:Key="CombinedCollection">
        <CollectionContainer Collection="{Binding Source={StaticResource ViewSource1}}" />
        <CollectionContainer Collection="{Binding Source={StaticResource ViewSource2}}" />
    </CompositeCollection>
</Window.Resources>

<Grid>
    <StackPanel Margin="0,250,0,0">
        <TreeView ItemsSource="{StaticResource CombinedCollection}">
        <TreeView.Resources>
            <DataTemplate DataType="{x:Type viewModels:TotalViewModel}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding Path=Model.FailNum}" Margin="5,0" />
                    <TextBlock Text="{Binding Path=Model.FailRate}" Margin="5,0" />
                </StackPanel>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
    </StackPanel>
    <!--<StackPanel>
        <TreeView>
            <TreeViewItem Header="Item1-1">
                <TreeViewItem Header="Item1-1-1" />
                <TreeViewItem Header="Item1-1-2" />
            </TreeViewItem>
            <TreeViewItem Header="Item1-2">
                <TreeViewItem Header="Item1-2-1" />
            </TreeViewItem>
        </TreeView>
    </StackPanel>-->
</Grid>

MainWindow.xaml.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using TwoListBoxes.Views;

namespace TwoListBoxes
{
    public partial class MainWindow : Window
    {
        List<string> SelectedTestList = new List<string>() { "Test_1", "Test_2" };

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ConfirmButton_Click(object sender, RoutedEventArgs e)
        {
            new CalcWindow(SelectedTestList).Show();
        }
    }
}

MainWindow.xaml

<Window x:Class="TwoListBoxes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test Selection" Height="375" Width="700">

<Grid>
    <ListBox Margin="91,32,0,40" Name="LeftListBox" HorizontalAlignment="Left" Width="168" Background="AntiqueWhite" />
    <ListBox Margin="0,31,89,41" Name="RightListBox" HorizontalAlignment="Right" Width="176" Background="AntiqueWhite"/>
        <Button Name="AddButton" Height="27" Margin="292,97,294,0" VerticalAlignment="Top"
            >Add &gt;&gt;</Button>
        <Button Name="RemoveButton" Margin="292,0,294,100"
            Height="28" VerticalAlignment="Bottom">&lt;&lt; Remove</Button>
    <Button Name="ConfirmButton" Content="Confirm" Margin="292,0,294,10" VerticalAlignment="Bottom" Click="ConfirmButton_Click"/>
</Grid>

В первом окне, пожалуйста, нажмите кнопку «Подтвердить». («Test_1» и «Test_2» уже жестко запрограммированы как элементы SelectedTestList.) Вы НЕ увидите никакого содержимого TreeView.

Чтобы показать содержимое, закомментируйте конструкторы MainViewModel и попытайтесь НЕ передавать параметр в CalcWindow. Вы увидите «123 45.6» как содержимое TreeView (на этот раз они жестко запрограммированы, но на самом деле эти числа должны генерироваться после того, как SelectedTestList используется в качестве ключа поиска).

Почемутакое поведение с / без параметра в конструкторе? Есть ли обходной путь? Заранее спасибо.

...