嵌入式winform图表是否可以绑定到WPF中的可观察集合

时间:2017-01-16 15:05:43

标签: c# .net wpf winforms xaml

我想在WPF窗口中嵌入一个winform图表控件,该窗口应绑定到通过在WPF DataGrid中输入数据填充的observablecollection。 需要observablecollection,因为我使用WPF-DataGrid填充它,我可以在其中插入或更新数据。

所以我在WPF项目中添加了以下依赖项: - System.Windows.Forms - System.Windows.Forms.DataVisualization

对于第一个测试,我在WPF窗口的构造函数中硬编码了observablecollection中的一些数据并绑定了图表控件。 在这种情况下,图表中的显示工作正常。

但在最终版本中,我想在DataGrid中插入和/或更新数据,图表将同时显示该数据。 有可能管理吗?

以下是窗口和类的代码示例。

WPF窗口MainWindow.xaml:

<Window x:Class="StepFunctions.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
        xmlns:winformchart="clr-namespace:System.Windows.Forms.DataVisualization.Charting;assembly=System.Windows.Forms.DataVisualization"
        xmlns:local="clr-namespace:StepFunctions"
        mc:Ignorable="d"
        Title="StepFunctions"
        Height="350"
        Width="525">
    <Grid x:Name="maingrid">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!--DataGrid for insert and update of step function data-->
        <DataGrid x:Name="grd_stepdata"
                  Grid.Row="0"
                  Grid.Column="0"
                  Margin="5"
                  AutoGenerateColumns="False"
                  CanUserAddRows="True"
                  RowEditEnding="grd_stepdata_RowEditEnding"
                  ItemsSource="{Binding StepDataSource, NotifyOnSourceUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <DataGrid.Columns>
                <DataGridTextColumn x:Name="col_LowerComparer" Binding="{Binding LowerComparer, NotifyOnTargetUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Lower comparer"/>
                <DataGridTextColumn x:Name="col_LowerBound" Binding="{Binding LowerBound, NotifyOnTargetUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Lower bound"/>
                <DataGridTextColumn x:Name="col_StepValue" Binding="{Binding StepValue, NotifyOnTargetUpdated=True, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Value"/>
            </DataGrid.Columns>
        </DataGrid>

        <!--Chart for displaying the step function data-->
        <WindowsFormsHost x:Name="host"
                          Grid.Row="0"
                          Grid.Column="1"
                          Margin="5">
            <winformchart:Chart x:Name="myWinformChart"
                                Dock="Fill">
                <winformchart:Chart.Series>
                    <winformchart:Series Name="series" ChartType="Line"/>
                </winformchart:Chart.Series>
                <winformchart:Chart.ChartAreas>
                    <winformchart:ChartArea/>
                </winformchart:Chart.ChartAreas>
            </winformchart:Chart>
        </WindowsFormsHost>

        <!--Button for test-->
        <Button x:Name="btn_do"
                Grid.Row="2"
                Grid.Column="0"
                Margin="5"
                Click="btn_do_Click">Do it</Button>
    </Grid>
</Window>

MainWindow.xaml的代码隐藏:

using StepFunctions.ViewModels;
using System.Windows;
using System.Windows.Controls;

namespace StepFunctions
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowViewModel vm = new MainWindowViewModel();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = vm;

            // These lines are just for the first test.
            // Normally these lines would be out-commented.
            AddStepdata();
            ChartDataRefresh();
        }

        // When the user leaves a DataGrid-row after insert or update the chart shall be refreshed.
        private void grd_stepdata_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
        {
            ChartDataRefresh();
        }

        private void AddStepdata()
        {
            vm.StepDataSource.Add(new StepData("<", 10, 1));
            vm.StepDataSource.Add(new StepData("<", 100, 2));
            vm.StepDataSource.Add(new StepData("<", 1000, 3));
        }

        private void ChartDataRefresh()
        {
            myWinformChart.DataSource = vm.StepDataSource;
            myWinformChart.Series["series"].XValueMember = "LowerBound";
            myWinformChart.Series["series"].YValueMembers = "StepValue";
        }

        /// <summary>
        /// For testing the refresh of the chart after the window was loaded.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btn_do_Click(object sender, RoutedEventArgs e)
        {
            AddStepdata();
            ChartDataRefresh();
        }

    }
}

viewmodel:

using System.Collections.ObjectModel;
using System.ComponentModel;

namespace StepFunctions.ViewModels
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        /// <summary>
        /// Eventhandler for signalising that a property has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        private ObservableCollection<StepData> stepdataSource = new ObservableCollection<StepData>();

        public ObservableCollection<StepData> StepDataSource
        {
            get { return stepdataSource; }
            set
            {
                stepdataSource = value;
                RaisePropertyChanged("StepDataSource");
            }
        }

        /// <summary>
        /// Informs the target which is bound to a property, that it's source was changed and that it shall update.
        /// </summary>
        /// <param name="propertyName">The name of the property.</param>
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}

最后是类StepData,它是observablecollection的基础:

namespace StepFunctions.ViewModels
{
    /// <summary>
    /// Class for data of stepfunctions.
    /// </summary>
    public class StepData
    {
        /// <summary>
        /// The constructor.
        /// </summary>
        public StepData()
        {
            // Do nothing
        }

        public StepData(string lowerComparer, double lowerBound, double stepValue)
        {
            LowerComparer = lowerComparer;
            LowerBound = lowerBound;
            StepValue = stepValue;
        }

        public string LowerComparer { get; set; }

        public double LowerBound { get; set; }

        public double StepValue { get; set; }

    }
}

1 个答案:

答案 0 :(得分:0)

我明白了! 图表必须在代码隐藏中生成,而不是在XAML中生成。

因此ChartDataRefresh方法必须如此:

private void ChartDataRefresh()
{
    Chart myWinformChart = new Chart();
    myWinformChart.Dock = System.Windows.Forms.DockStyle.Fill;
    Series mySeries = new Series("series");
    mySeries.ChartType = SeriesChartType.Line;
    myWinformChart.Series.Add(mySeries);
    ChartArea myArea = new ChartArea();
    myWinformChart.ChartAreas.Add(myArea);
    myWinformChart.DataSource = vm.StepDataSource;
    myWinformChart.Series["series"].XValueMember = "LowerBound";
    myWinformChart.Series["series"].YValueMembers = "StepValue";
    host.Child = myWinformChart;
}

在WPF-DataGrid中输入数据时,将刷新Winform图表控件,并将数据显示为一行,以检查给定数据是否正确。