QA@IT
«回答へ戻る

5599
 Livetではない場合の書き方もコメントに載せておきました(見づらいかもしれませんが)
 
 **MainWindowViewModel.cs**
-```
+```csharp
 public class InspectViewModel :ViewModel {
 // public class InspectViewModel :INotifyPropertyChanged {
     public static PointCollectionConverter pointCollectionConverter;
 
 ポイントとなるのは、Pointsの型が`ObservableCollection<Point>`であることです。
 
-# 一旦投稿します。
+---
+さて、最終的にXAMLでこのInspectViewModel.Points をバインドするわけですが、これはPointCollectionではないのでそのままではバインドできません。
+PointCollectionに変換するコンバーターを用意する必要があります。
+http://stackoverflow.com/questions/21618046/wpf-path-binding-to-pointcollection-not-updating-ui
 
-続きも今日書きます。
+**MainWindowViewModel.cs**
+```csharp
+public class PointCollectionConverter : IValueConverter {
+
+    public object Convert(object value, System.Type targetType, object parameter
+                          , System.Globalization.CultureInfo culture) {
+
+        if (value.GetType() == typeof(ObservableCollection<Point>) 
+            && targetType == typeof(PointCollection)) {
+
+            var pointCollection = new PointCollection();
+            foreach (var point in value as ObservableCollection<Point>)
+                pointCollection.Add(point);
+            return pointCollection;
+        }
+        return null;
+    }
+
+    public object ConvertBack(object value, System.Type targetType, object parameter
+                              , System.Globalization.CultureInfo culture) {
+        return null; // 不要
+    }
+}
+```
+
+---
+
+最後に XAMLを編集してこれらをバインドします。
+`LivetWPFApplication1` は適宜置き換えてください。
+
+* `xmlns:local`が追加されています。
+* `<Window.Resources>`にコンバータを登録しています。
+* 既存のPolylineはそのままに新しいPolylineをGridに追加しています。
+* DataContextは変えていませんがコンストラクタで変更していますので実際にバインドされるのはInspectViewModelという事に気を付けてください。
+
+```
+<Window x:Class="LivetWPFApplication1.Views.MainWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
+        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
+        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
+        xmlns:v="clr-namespace:LivetWPFApplication1.Views"
+        xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
+        xmlns:local="clr-namespace:LivetWPFApplication1.ViewModels"
+        Title="MainWindow" Height="350" Width="525">
+    <Window.Resources>
+        <local:PointCollectionConverter x:Key="pointCollectionConverter"  />
+    </Window.Resources>
+    <Window.DataContext>
+        <vm:MainWindowViewModel/>
+    </Window.DataContext>
+    
+    <i:Interaction.Triggers>
+        <i:EventTrigger EventName="ContentRendered">
+            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
+        </i:EventTrigger>
+        <i:EventTrigger EventName="Closed">
+            <l:DataContextDisposeAction/>
+        </i:EventTrigger>
+
+    </i:Interaction.Triggers>
+    
+    <Grid>
+        <Polyline x:Name="BluePolyLine" Stroke="Blue" Points="{Binding Path=BluePlolyLinePoints}" />
+        <Polyline x:Name="RedPolyLine" Stroke="Red"></Polyline>
+        <Polyline Stretch="Fill" Grid.Column="0" Name="polyline" Stroke="Red" Points="{Binding Points, Converter={StaticResource pointCollectionConverter}}">
+        </Polyline>
+    </Grid>
+</Window>
+```
+
+これで期待された動作になると思います。

細かい質問には答えられないかもしれませんが、とりあえず動作したものを。

Livetに限らず、BindしたCollectionの内容変化を通知しないといけないが、PointCollectionではそれができないので別の物を使う必要があるようです。
ここでは ObservableCollection<Points> を使用することにします。

http://stackoverflow.com/questions/3960101/polyline-using-databinding-and-pointcollection-for-continuous-update

提示していただいたコードをベースに変更を加えていきます。
まず、XAMLの方でDataContextを設定してますが、それを後で作成する検証用ViewModelに差し替えます。

MainWindow.xaml.cs

public MainWindow()
{
   InitializeComponent();
   //var vm = (MainWindowViewModel)DataContext;
   //vm.RedPolyline = RedPolyLine;
   this.DataContext = new InspectViewModel();
}

つづいてそのInspectViewModelを作成します。
面倒だったのでファイルは追加せずに既存のMainWindowViewModel.csファイルに追記してます。

Livetではない場合の書き方もコメントに載せておきました(見づらいかもしれませんが)

MainWindowViewModel.cs

public class InspectViewModel :ViewModel {
// public class InspectViewModel :INotifyPropertyChanged {
    public static PointCollectionConverter pointCollectionConverter;

    private DispatcherTimer timer = new DispatcherTimer();
    private Random rnd = new Random();

    public InspectViewModel() {
        // Livet(ViewModel継承)ではなく、INotifyPropertyChangedで実装する場合
        // は Initializeメソッドの中身をここに。
    }

    public void Initialize() {

        timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
        timer.Tick += (sender, e) => {
            var x = rnd.NextDouble() * 525;
            var y = rnd.NextDouble() * 320;
            var point = new Point(x, y);
            _points.Add(point);


            // Livetの場合
            RaisePropertyChanged("Points");

            // INotifyPropertyChangedの場合
            // PropertyChanged(this, new PropertyChangedEventArgs("Points"));  

        };

        timer.Start();
    }

    private ObservableCollection<Point> _points = new ObservableCollection<Point>();
    public ObservableCollection<Point> Points {
        get { return _points; }
    }

    // INotifyPropertyChangedの場合
    // public event PropertyChangedEventHandler PropertyChanged;
}

ポイントとなるのは、Pointsの型がObservableCollection<Point>であることです。


さて、最終的にXAMLでこのInspectViewModel.Points をバインドするわけですが、これはPointCollectionではないのでそのままではバインドできません。
PointCollectionに変換するコンバーターを用意する必要があります。
http://stackoverflow.com/questions/21618046/wpf-path-binding-to-pointcollection-not-updating-ui

MainWindowViewModel.cs

public class PointCollectionConverter : IValueConverter {

    public object Convert(object value, System.Type targetType, object parameter
                          , System.Globalization.CultureInfo culture) {

        if (value.GetType() == typeof(ObservableCollection<Point>) 
            && targetType == typeof(PointCollection)) {

            var pointCollection = new PointCollection();
            foreach (var point in value as ObservableCollection<Point>)
                pointCollection.Add(point);
            return pointCollection;
        }
        return null;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter
                              , System.Globalization.CultureInfo culture) {
        return null; // 不要
    }
}

最後に XAMLを編集してこれらをバインドします。
LivetWPFApplication1 は適宜置き換えてください。

  • xmlns:localが追加されています。
  • <Window.Resources>にコンバータを登録しています。
  • 既存のPolylineはそのままに新しいPolylineをGridに追加しています。
  • DataContextは変えていませんがコンストラクタで変更していますので実際にバインドされるのはInspectViewModelという事に気を付けてください。
<Window x:Class="LivetWPFApplication1.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:LivetWPFApplication1.Views"
        xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
        xmlns:local="clr-namespace:LivetWPFApplication1.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:PointCollectionConverter x:Key="pointCollectionConverter"  />
    </Window.Resources>
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>

    </i:Interaction.Triggers>

    <Grid>
        <Polyline x:Name="BluePolyLine" Stroke="Blue" Points="{Binding Path=BluePlolyLinePoints}" />
        <Polyline x:Name="RedPolyLine" Stroke="Red"></Polyline>
        <Polyline Stretch="Fill" Grid.Column="0" Name="polyline" Stroke="Red" Points="{Binding Points, Converter={StaticResource pointCollectionConverter}}">
        </Polyline>
    </Grid>
</Window>

これで期待された動作になると思います。

細かい質問には答えられないかもしれませんが、とりあえず動作したものを。

Livetに限らず、BindしたCollectionの内容変化を通知しないといけないが、`PointCollection`ではそれができないので別の物を使う必要があるようです。
ここでは `ObservableCollection<Points>` を使用することにします。

http://stackoverflow.com/questions/3960101/polyline-using-databinding-and-pointcollection-for-continuous-update

提示していただいたコードをベースに変更を加えていきます。
まず、XAMLの方でDataContextを設定してますが、それを後で作成する検証用ViewModelに差し替えます。

**MainWindow.xaml.cs**
```csharp
public MainWindow()
{
   InitializeComponent();
   //var vm = (MainWindowViewModel)DataContext;
   //vm.RedPolyline = RedPolyLine;
   this.DataContext = new InspectViewModel();
}
```

つづいてその`InspectViewModel`を作成します。
面倒だったのでファイルは追加せずに既存のMainWindowViewModel.csファイルに追記してます。

Livetではない場合の書き方もコメントに載せておきました(見づらいかもしれませんが)

**MainWindowViewModel.cs**
```csharp
public class InspectViewModel :ViewModel {
// public class InspectViewModel :INotifyPropertyChanged {
    public static PointCollectionConverter pointCollectionConverter;

    private DispatcherTimer timer = new DispatcherTimer();
    private Random rnd = new Random();

    public InspectViewModel() {
        // Livet(ViewModel継承)ではなく、INotifyPropertyChangedで実装する場合
        // は Initializeメソッドの中身をここに。
    }

    public void Initialize() {

        timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
        timer.Tick += (sender, e) => {
            var x = rnd.NextDouble() * 525;
            var y = rnd.NextDouble() * 320;
            var point = new Point(x, y);
            _points.Add(point);


            // Livetの場合
            RaisePropertyChanged("Points");

            // INotifyPropertyChangedの場合
            // PropertyChanged(this, new PropertyChangedEventArgs("Points"));  

        };

        timer.Start();
    }

    private ObservableCollection<Point> _points = new ObservableCollection<Point>();
    public ObservableCollection<Point> Points {
        get { return _points; }
    }

    // INotifyPropertyChangedの場合
    // public event PropertyChangedEventHandler PropertyChanged;
}
```

ポイントとなるのは、Pointsの型が`ObservableCollection<Point>`であることです。

---
さて、最終的にXAMLでこのInspectViewModel.Points をバインドするわけですが、これはPointCollectionではないのでそのままではバインドできません。
PointCollectionに変換するコンバーターを用意する必要があります。
http://stackoverflow.com/questions/21618046/wpf-path-binding-to-pointcollection-not-updating-ui

**MainWindowViewModel.cs**
```csharp
public class PointCollectionConverter : IValueConverter {

    public object Convert(object value, System.Type targetType, object parameter
                          , System.Globalization.CultureInfo culture) {

        if (value.GetType() == typeof(ObservableCollection<Point>) 
            && targetType == typeof(PointCollection)) {

            var pointCollection = new PointCollection();
            foreach (var point in value as ObservableCollection<Point>)
                pointCollection.Add(point);
            return pointCollection;
        }
        return null;
    }

    public object ConvertBack(object value, System.Type targetType, object parameter
                              , System.Globalization.CultureInfo culture) {
        return null; // 不要
    }
}
```

---

最後に XAMLを編集してこれらをバインドします。
`LivetWPFApplication1` は適宜置き換えてください。

* `xmlns:local`が追加されています。
* `<Window.Resources>`にコンバータを登録しています。
* 既存のPolylineはそのままに新しいPolylineをGridに追加しています。
* DataContextは変えていませんがコンストラクタで変更していますので実際にバインドされるのはInspectViewModelという事に気を付けてください。

```
<Window x:Class="LivetWPFApplication1.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:LivetWPFApplication1.Views"
        xmlns:vm="clr-namespace:LivetWPFApplication1.ViewModels"
        xmlns:local="clr-namespace:LivetWPFApplication1.ViewModels"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:PointCollectionConverter x:Key="pointCollectionConverter"  />
    </Window.Resources>
    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>
    
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>

    </i:Interaction.Triggers>
    
    <Grid>
        <Polyline x:Name="BluePolyLine" Stroke="Blue" Points="{Binding Path=BluePlolyLinePoints}" />
        <Polyline x:Name="RedPolyLine" Stroke="Red"></Polyline>
        <Polyline Stretch="Fill" Grid.Column="0" Name="polyline" Stroke="Red" Points="{Binding Points, Converter={StaticResource pointCollectionConverter}}">
        </Polyline>
    </Grid>
</Window>
```

これで期待された動作になると思います。

回答を投稿

細かい質問には答えられないかもしれませんが、とりあえず動作したものを。

Livetに限らず、BindしたCollectionの内容変化を通知しないといけないが、PointCollectionではそれができないので別の物を使う必要があるようです。
ここでは ObservableCollection<Points> を使用することにします。

http://stackoverflow.com/questions/3960101/polyline-using-databinding-and-pointcollection-for-continuous-update

提示していただいたコードをベースに変更を加えていきます。
まず、XAMLの方でDataContextを設定してますが、それを後で作成する検証用ViewModelに差し替えます。

MainWindow.xaml.cs

public MainWindow()
{
   InitializeComponent();
   //var vm = (MainWindowViewModel)DataContext;
   //vm.RedPolyline = RedPolyLine;
   this.DataContext = new InspectViewModel();
}

つづいてそのInspectViewModelを作成します。
面倒だったのでファイルは追加せずに既存のMainWindowViewModel.csファイルに追記してます。

Livetではない場合の書き方もコメントに載せておきました(見づらいかもしれませんが)

MainWindowViewModel.cs

public class InspectViewModel :ViewModel {
// public class InspectViewModel :INotifyPropertyChanged {
    public static PointCollectionConverter pointCollectionConverter;

    private DispatcherTimer timer = new DispatcherTimer();
    private Random rnd = new Random();

    public InspectViewModel() {
        // Livet(ViewModel継承)ではなく、INotifyPropertyChangedで実装する場合
        // は Initializeメソッドの中身をここに。
    }

    public void Initialize() {

        timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
        timer.Tick += (sender, e) => {
            var x = rnd.NextDouble() * 525;
            var y = rnd.NextDouble() * 320;
            var point = new Point(x, y);
            _points.Add(point);


            // Livetの場合
            RaisePropertyChanged("Points");

            // INotifyPropertyChangedの場合
            // PropertyChanged(this, new PropertyChangedEventArgs("Points"));  

        };

        timer.Start();
    }

    private ObservableCollection<Point> _points = new ObservableCollection<Point>();
    public ObservableCollection<Point> Points {
        get { return _points; }
    }

    // INotifyPropertyChangedの場合
    // public event PropertyChangedEventHandler PropertyChanged;
}

ポイントとなるのは、Pointsの型がObservableCollection<Point>であることです。

一旦投稿します。

続きも今日書きます。

細かい質問には答えられないかもしれませんが、とりあえず動作したものを。

Livetに限らず、BindしたCollectionの内容変化を通知しないといけないが、`PointCollection`ではそれができないので別の物を使う必要があるようです。
ここでは `ObservableCollection<Points>` を使用することにします。

http://stackoverflow.com/questions/3960101/polyline-using-databinding-and-pointcollection-for-continuous-update

提示していただいたコードをベースに変更を加えていきます。
まず、XAMLの方でDataContextを設定してますが、それを後で作成する検証用ViewModelに差し替えます。

**MainWindow.xaml.cs**
```csharp
public MainWindow()
{
   InitializeComponent();
   //var vm = (MainWindowViewModel)DataContext;
   //vm.RedPolyline = RedPolyLine;
   this.DataContext = new InspectViewModel();
}
```

つづいてその`InspectViewModel`を作成します。
面倒だったのでファイルは追加せずに既存のMainWindowViewModel.csファイルに追記してます。

Livetではない場合の書き方もコメントに載せておきました(見づらいかもしれませんが)

**MainWindowViewModel.cs**
```
public class InspectViewModel :ViewModel {
// public class InspectViewModel :INotifyPropertyChanged {
    public static PointCollectionConverter pointCollectionConverter;

    private DispatcherTimer timer = new DispatcherTimer();
    private Random rnd = new Random();

    public InspectViewModel() {
        // Livet(ViewModel継承)ではなく、INotifyPropertyChangedで実装する場合
        // は Initializeメソッドの中身をここに。
    }

    public void Initialize() {

        timer.Interval = new TimeSpan(0, 0, 0, 0, 200);
        timer.Tick += (sender, e) => {
            var x = rnd.NextDouble() * 525;
            var y = rnd.NextDouble() * 320;
            var point = new Point(x, y);
            _points.Add(point);


            // Livetの場合
            RaisePropertyChanged("Points");

            // INotifyPropertyChangedの場合
            // PropertyChanged(this, new PropertyChangedEventArgs("Points"));  

        };

        timer.Start();
    }

    private ObservableCollection<Point> _points = new ObservableCollection<Point>();
    public ObservableCollection<Point> Points {
        get { return _points; }
    }

    // INotifyPropertyChangedの場合
    // public event PropertyChangedEventHandler PropertyChanged;
}
```

ポイントとなるのは、Pointsの型が`ObservableCollection<Point>`であることです。

# 一旦投稿します。

続きも今日書きます。