【问题标题】:How to add new view when instantiating a new view model实例化新视图模型时如何添加新视图
【发布时间】:2019-07-27 00:24:56
【问题描述】:

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,当我在没有此类的情况下在主窗口中对其进行测试时,它的工作原理如下。

stackPanel.Children.Add(chart);

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

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

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

【问题讨论】:

    标签: wpf livecharts


    【解决方案1】:

    如果您想动态添加新图表,您必须使用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));
      }
    }
    

    【讨论】:

      【解决方案2】:

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

      也就是说,您应该在 xaml(或 xaml.cs)中实例化您的图表,然后将其属性绑定到 ViewModel。 要链接 View 和 ViewModel,视图的 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元素)

      【讨论】:

      • 他需要在该视图模型上实现 INotifyPropertyChanged。
      • 问题是我需要创建并添加到堆栈面板的图表数量未定义。它将基于记录运行时间。所以我真的不能只为 xaml 中的所有图表标记它吗?
      • @Ed 仅当他要更新这些值时,但是是的,通常应该在基类上实现!
      • 对我来说这个问题看起来很像他打算更新这些值。我们得到很多“为什么不更新?”问题;这不是一个闲散的问题。
      猜你喜欢
      • 2013-08-26
      • 1970-01-01
      • 2013-07-02
      • 1970-01-01
      • 1970-01-01
      • 2015-06-25
      • 1970-01-01
      • 2011-10-21
      • 1970-01-01
      相关资源
      最近更新 更多