如何在实例化新视图模型时添加新视图

How to add new view when instantiating a new view model

WPF 新手,不确定如何以编程方式实例化包装新图表及其数据集合的新视图模型。目前,它包含以下内容,但不确定最佳设置方式。

class ChartViewModel
    {
        public ChartViewModel()
        {
            CartesianChart chart = new CartesianChart();
            chart.Series = new SeriesCollection
            {
                new GLineSeries
                {
                    Title = "Pressure",
                    Values = new GearedValues<double>(),
                },
                new GLineSeries
                {
                    Title = "Pulse",
                    Values = new GearedValues<int>(),
                }
            };  
        }
    }

然后,我需要将新图表添加到视图中。 CartesianChart 对象是 UIElement,当我只是在 main window 中测试它时它的工作原理如下 class.

stackPanel.Children.Add(chart);

但是 class 似乎无法访问 xaml 而且我无法添加实际的视图模型 class 因为那不是 UIElement,只有图表是。基本上每次以前的图表填满这样的东西时都需要创建一个新的图表实例:

ChartViewModel tempChart = new ChartViewModel();
chartRepo.Add(tempChart); //chart repo is a list of ChartViewModels

因此它需要自己的 SeriesCollection 和 UIElement。感谢您的任何建议。

ViewModel 正在实例化一个图表,它是一个 UI 元素。 ViewModels 应该只公开带有 public getter(有时是 setter)的简单属性。视图应读取这些属性并相应地更改其 UI 元素。 ViewModel 通常不包含 UI 个元素。

也就是说,您应该在 xaml(或 xaml.cs)中实例化您的图表,然后将其属性绑定到 ViewModel。 对于linkView和ViewModel,view的DataContext属性必须是ViewModel实例.

ViewModel 可以直接访问您的数据源(例如数据库)并将该源转换为可供 UI 元素使用的值。

例如,您的视图可能包含如下内容:

<livechart:CartesianChart>
    <livechart:CartesianChart.Series>
        <Series Title="{Binding FirstSeriesTitle}" Values="{Binding FirstSeriesValues}"/>
    </livechart:CartesianChart.Series>
</livechart:CartesianChart>

虽然您的 ViewModel 将具有

public class ChartViewModel
{
    public string FirstSeriesTitle { get; set; }

    public IEnumerable<ChartPoint> FirstSeriesValues { get; set; }
}

我建议您阅读一些有关 MVVM 模式的文章,以便更好地掌握它!

编辑::由于您需要可变数量的图表,您可能应该添加一个 ItemsControl,并将其 ItemsSource 设置为绑定到图表视图模型的 ObservableCollection。设置 itemscontrol 的 itemTemplate 属性 来设置每个项目的外观! (也就是说,图表和其他 ui 元素)

如果您想动态添加新图表,您必须使用 DataTemplate 来模板化图表数据。

构成图表的DataTemplate绑定了一个ChartDataModel。我们可以使用 ListView 来显示图表(数据模板)。视图模型 ChartViewModel 用作 ListView.ItemsSource 并包含一组 ChartData.
每个 ChartData 映射到一个新图表。

每当您在 ChartViewModel 中创建一个新的 ChartDataModel 并将其添加到 ChartModels 时,ListView 将自动创建一个新图表。

观点:

<ListView ItemsSource="{Binding ChartModels}">
  <ListView.DataContext>
    <ChartViewModel />
  </ListView.DataContext>

  <ListView.ItemTemplate>
    <DataTemplate DataType="ChartDataModel">
      <CartesianChart>
        <CartesianChart.Series>
          <LineSeries Title="Pressure" Values="{Binding PressureValues}" />
          <LineSeries Title="Pulse" Values="{Binding PulseValues}" />
        </CartesianChart.Series>
      </CartesianChart>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

型号:

class ChartDataModel
{
  public ChartDataModel()
  {
    this.PressureValues = new ChartValues<double>();
    this.PulseValues = new ChartValues<double>();
  }

  public ChartValues<double> PressureValues { get; set; }
  public ChartValues<double> PulseValues { get; set; }
}

视图模型:

class ChartViewModel : INotifyPropertyChanged
{
  public ChartViewModel()
  {
    this.ChartModels = new ObservableCollection<ChartDataModel>();
    CreateNewChart();
  }

  private void CreateNewChart()
  {
    var newChartDataModel = new ChartDataModel()
    {
      PressureDataValues = new ChartValues<double>()
      {
        10, 20, 30, 40, 50
      },
      PulseDataValues = new ChartValues<double>()
      {
        100, 200, 300, 400, 500
      }
    };

    this.ChartModels.Add(newChartDataModel);
  } 

  private ObservableCollection<ChartDataModel> chartModels;
  public ObservableCollection<ChartDataModel> ChartModels
  {
    get => this.chartModels;
    set
    {
      if (Equals(value, this.chartModels)) return;
      this.chartModels = value;
      OnPropertyChanged();
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;

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