使用 DataBinding 和 PointCollection 进行连续更新的折线

发布于 2024-09-27 14:42:47 字数 3169 浏览 4 评论 0原文


首先,我描述我想要实现的目标。我想要可视化连续的数据流(每秒最多 1000 个值,但可以减少)。该数据流应该可视化为图表 - 更准确地说,它是心电图等的可视化。 我的第一个想法是使用折线并将其绑定到点集合。这里的问题是 UI 上没有显示任何内容。也许这是完成这项任务的错误方法。欢迎更好的想法。到目前为止,这是我的代码。首先是视图:

 
<Canvas>
  <Polyline Points="{Binding Points}" Stroke="Red" StrokeThickness="2" />
</Canvas>

为了简单起见,即使我使用 MVVM 模式,我也使用代码隐藏。这也是我想要使用绑定而不仅仅是折线名称并添加值的原因。


public partial class MainWindow : Window
{
   private short[] data = new short[]{ 10,30,50,70,90,110,130,150,170,190,210 };
   private short[] data1 = new short[] { 15,14,16,13,17,12,18,11,19,10,24 };

    public MainWindow()
    {
        InitializeComponent();
        for (int i = 0; i < data.Length; i++)
        {
            Points.Add(new Point(data[i], data1[i]));
        }
    }

    private PointCollection _points = new PointCollection();
    public PointCollection Points
    {
        get { return _points; }
    }

}

I know that is no good coding style but for first tests its enough for me. I use array data for x-values and data1 for y-values. Can anyone tell me whats wrong with that binding? What's to be done for a continuous update of the view, whenever new values occur?
Thanks for your help in advance.

[更新新版本] 观点:


<Window.Resources>
        <my:PointCollectionConverter x:Key="myPointsConverter"/>
</Window.Resources>
    <Grid Name="grid">
        <Polyline x:Name="ekglineI" Points="{Binding Points, Converter={StaticResource myPointsConverter}}" Stroke="Red" StrokeThickness="2"  />
        <Button Content="Button" Click="button1_Click" />
</Grid>
The code-behind which draws a polyline on startup and later on when a button is clicked.

public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private short[] data = new short[] { 10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210 };
        private short[] data2 = new short[] { 230, 250, 270, 290, 300, 310, 330, 350, 370, 390, 410 };
        private short[] data1 = new short[] { 15, 14, 16, 13, 17, 12, 18, 11, 19, 10, 24 };

公共主窗口() { 初始化组件(); 网格.DataContext = this; for (int i = 0; i < data.Length; i++) { Points.Add(new Point(data[i], data1[i])); } } 公共事件 PropertyChangedEventHandler PropertyChanged; 私有 ObservableCollection _points = new ObservableCollection(); 公共 ObservableCollection 点 { 获取{返回_points; } }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 0; i < data2.Length; i++)
        {
            Points.Add(new Point(data2[i], data1[i]));
        }
        PropertyChanged(this, new PropertyChangedEventArgs("Points"));
    }

现在我想做的是摆脱这一行: grid.DataContext = this; 以便我可以使用我的 MVVM 或者还有其他可能性吗?

first of all I describe my objective I want to achive. I want to visualise a continuous data stream (maximum 1000 values per second but could be reduced). This data stream should be visualised as a chart - being more precise it's a visualisation of an ECG among other things.
My first idea was using polyline and bind it to a point collection. The problem here is that nothing is shown on the UI. Perhaps it's a wrong aproach for this task. Better ideas are welcomed. Here ist my code so far. First the View:

 
<Canvas>
  <Polyline Points="{Binding Points}" Stroke="Red" StrokeThickness="2" />
</Canvas>

For the sake of simplicity I use the code-behind even though I use the MVVM-pattern. That's also the reason why I want to use the binding and not just the name of the polyline and add the values.


public partial class MainWindow : Window
{
   private short[] data = new short[]{ 10,30,50,70,90,110,130,150,170,190,210 };
   private short[] data1 = new short[] { 15,14,16,13,17,12,18,11,19,10,24 };

    public MainWindow()
    {
        InitializeComponent();
        for (int i = 0; i < data.Length; i++)
        {
            Points.Add(new Point(data[i], data1[i]));
        }
    }

    private PointCollection _points = new PointCollection();
    public PointCollection Points
    {
        get { return _points; }
    }

}


I know that is no good coding style but for first tests its enough for me. I use array data for x-values and data1 for y-values. Can anyone tell me whats wrong with that binding? What's to be done for a continuous update of the view, whenever new values occur?
Thanks for your help in advance.

[Updated new version]
The view:


<Window.Resources>
        <my:PointCollectionConverter x:Key="myPointsConverter"/>
</Window.Resources>
    <Grid Name="grid">
        <Polyline x:Name="ekglineI" Points="{Binding Points, Converter={StaticResource myPointsConverter}}" Stroke="Red" StrokeThickness="2"  />
        <Button Content="Button" Click="button1_Click" />
</Grid>


The code-behind which draws a polyline on startup and later on when a button is clicked.


public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private short[] data = new short[] { 10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210 };
        private short[] data2 = new short[] { 230, 250, 270, 290, 300, 310, 330, 350, 370, 390, 410 };
        private short[] data1 = new short[] { 15, 14, 16, 13, 17, 12, 18, 11, 19, 10, 24 };

public MainWindow() { InitializeComponent(); grid.DataContext = this; for (int i = 0; i < data.Length; i++) { Points.Add(new Point(data[i], data1[i])); } } public event PropertyChangedEventHandler PropertyChanged; private ObservableCollection _points = new ObservableCollection(); public ObservableCollection Points { get { return _points; } }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 0; i < data2.Length; i++)
        {
            Points.Add(new Point(data2[i], data1[i]));
        }
        PropertyChanged(this, new PropertyChangedEventArgs("Points"));
    }

Now what I want to do is getting rid of this line: grid.DataContext = this; so that I can use my MVVM or is there another possibility?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

讽刺将军 2024-10-04 14:42:47

为了将 Polyline Points 属性成功绑定到您的视图模型(即在绑定的 PointCollection 更改时更新它),您应该避免将 PointCollection 更改为集合(清除、添加等)。 Polyline 不会注意到这一点,即使使用自定义转换器绑定到 ObservableCollection of Points 也无济于事。

相反,您应该将 PointCollection 视为一个属性:使用新创建的 PointCollection 设置它,并触发 NotifyPropertyChanged 事件:

    private PointCollection points = new PointCollection();
    public PointCollection Points 
    {
        get { return points; }
        set
        {
            points = value;
            NotifyPropertyChanged("Points");
        }
    }

    public void SomeUpdateFunc() 
    {
        PointCollection pc = new PointCollection();

        // Do some adding: pc.Add(new Point(x, y)); etc

        this.Points = pc; // set via the setter, so the notification will fire
    }

现在折线应该正确更新,祝您好运!

In order to bind the Polyline Points attribute to your viewmodel successfully (i.e. to have it update when the bound PointCollection changes), you should avoid changing the PointCollection as a collection (Clear, Add, etc). The Polyline will not notice that, even binding to an ObservableCollection of Points with a custom converter will not help.

Instead, you should consider your PointCollection as a property: set it with a newly created PointCollection, and fire a NotifyPropertyChanged event:

    private PointCollection points = new PointCollection();
    public PointCollection Points 
    {
        get { return points; }
        set
        {
            points = value;
            NotifyPropertyChanged("Points");
        }
    }

    public void SomeUpdateFunc() 
    {
        PointCollection pc = new PointCollection();

        // Do some adding: pc.Add(new Point(x, y)); etc

        this.Points = pc; // set via the setter, so the notification will fire
    }

Now the Polyline should be updated properly, good luck!

离不开的别离 2024-10-04 14:42:47

Kai 要将更改通知传播到您的绑定,您应该使用实现更改通知的集合,PointCollection 不会执行此操作。您可以创建自己的集合,但我建议使用 ObservableCollection

另外这里有一个类似的 SO post 其中还涉及一些其他选项,使 UI 知道您的更改。

Kai to make the change notification propagate to your bindings you should be making use of a collection which implements change notificaiton, PointCollection does not do this. You could create your own collection however I'd recommend making use of ObservableCollection<T>.

In addition here is a similar SO post which also touches on a few other options for making the UI aware of your changes.

最近可好 2024-10-04 14:42:47

至少有一种可能的方法可以删除 grid.DataContext = this;

添加 绑定到relativesource到网格本身。在这种情况下,xaml 文件将如下所示

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:WpfApplication2">
<Grid Name="grid" DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:MainWindow, AncestorLevel=1}}">
    <Canvas>
        <Polyline Points="{Binding Points}" Stroke="Red" StrokeThickness="2" />
    </Canvas>
</Grid>

后面的代码会是这样的

 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Text;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 using System.ComponentModel;

 namespace WpfApplication2
 {
    public partial class MainWindow : Window , INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < data.Length; i++)
            {
                 Points.Add(new Point(data[i], data1[i]));
            }
            NotifyPropertyChanged("Points");                
        }

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public PointCollection Points { get { return _points; } }

        public event PropertyChangedEventHandler PropertyChanged;
        private PointCollection _points = new PointCollection();
        private short[] data = new short[] { 10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210 };
        private short[] data1 = new short[] { 15, 14, 16, 13, 17, 12, 18, 11, 19, 10, 24 };


    }
}

There is at least one possible way to remove grid.DataContext = this;

Add Binding to RelativeSource to the grid itself. In this case the xaml file will looks like

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:WpfApplication2">
<Grid Name="grid" DataContext="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:MainWindow, AncestorLevel=1}}">
    <Canvas>
        <Polyline Points="{Binding Points}" Stroke="Red" StrokeThickness="2" />
    </Canvas>
</Grid>

And the code behind will be like this

 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Text;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Data;
 using System.Windows.Documents;
 using System.Windows.Input;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
 using System.ComponentModel;

 namespace WpfApplication2
 {
    public partial class MainWindow : Window , INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();

            for (int i = 0; i < data.Length; i++)
            {
                 Points.Add(new Point(data[i], data1[i]));
            }
            NotifyPropertyChanged("Points");                
        }

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        public PointCollection Points { get { return _points; } }

        public event PropertyChangedEventHandler PropertyChanged;
        private PointCollection _points = new PointCollection();
        private short[] data = new short[] { 10, 30, 50, 70, 90, 110, 130, 150, 170, 190, 210 };
        private short[] data1 = new short[] { 15, 14, 16, 13, 17, 12, 18, 11, 19, 10, 24 };


    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文