もくじ
⇒https://qiita.com/tera1707/items/4fda73d86eded283ec4f
やりたいこと
System.Windows.Point
クラスと、System.Windows.Media.PointCollection
クラスを使って、xamlで作った画面に線を引きたい。
※System.Drawing.Point
クラスではなくSystem.Windows.Point
クラス。
流れ
- 準備
-
System.Windows.Point
を持たせるクラスに(以下、Pointクラスと言う)
InotifyPropertyChanged
を実装する -
Point
をPointCollection
に変換してくれるコンバータをつくる
-
- 線を書く
-
System.Windows.Point
のObservableCollectionをつくる - 好きなタイミングで、線を引きたい座標を入れた
Point
をObservableCollectionにAddする - OnPropertyChanged(PropertyChanged)を実行する
- →PointのObservableCollectionにあった線が描画される
-
前提
.NET core 3.1で実験。
サンプル
画面
MainWindow.xaml
<Window x:Class="WpfApp57.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:local="clr-namespace:WpfApp57"
xmlns:conv="clr-namespace:Converter"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Name="root">
<Window.Resources>
<conv:ListPointToPointCollectionConverter x:Key="ListPointToPointCollectionConverter" />
</Window.Resources>
<Grid>
<Canvas>
<!-- 線 -->
<Polyline Name="MyLine" Stroke="Red" StrokeThickness="1"
Points="{Binding Points, ElementName=root, Converter={StaticResource ListPointToPointCollectionConverter}}"/>
<!-- ボタン -->
<Button Content="Button" Height="100" Canvas.Left="10" Canvas.Top="324" Width="100" Click="Button_Click"/>
</Canvas>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows;
using System.Collections.ObjectModel;
namespace WpfApp57
{
/// <summary>
/// ボタンをおしたら、サインカーブを書く
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
// ------------------------------------------------
public ObservableCollection<Point> Points
{
get { return _points; }
set { _points = value; OnPropertyChanged(nameof(Points)); }
}
private ObservableCollection<Point> _points = new ObservableCollection<Point>();
public MainWindow()
{
InitializeComponent();
// Point追加時に自動でOnPropertyChangedしてくれるようにする
Points.CollectionChanged += ((sender, e) =>
{
var oc = sender as ObservableCollection<Point>;
OnPropertyChanged(nameof(Points));
Debug.WriteLine("count = " + oc.Count);
});
}
private double y = 150.0;
private void Button_Click(object sender, RoutedEventArgs e)
{
var _ = Task.Run(() =>
{
this.Dispatcher.Invoke(new Action(async () =>
{
for (int i = 0; i < 100; i++)
{
Points.Add(new Point((double)i, y + 150.0 * Math.Sin((double)i / (Math.PI))));
OnPropertyChanged(nameof(Points));
await Task.Delay(30);
}
}));
});
}
}
}
コンバータ
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Collections.ObjectModel;
namespace Converter
{
public class ListPointToPointCollectionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var points = (ObservableCollection<Point>)value;
return points != null ? new PointCollection(points) : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
実行イメージ
備考
試してないが、コンバータを使わなくても、コード内でPointをPointCollectionにしてもよいと思う。
コード