3

ポリラインのポイントを ObservableCollection(Of Point) にバインドすることに固執しています。

<UserControl
x:Class="GL.MainPage"
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"
mc:Ignorable="d"
d:DesignHeight="640" d:DesignWidth="840">
<Grid x:Name="LayoutRoot" Background="#ff444444">
    <Canvas Background="#333333" Width="800" Height="600">
        <Polyline x:Name="Linie" Stroke="Yellow" StrokeThickness="2" Canvas.Left="0" Canvas.Top="0" Width="800" Height="600" Fill="Gray" Points="{Binding Punkte}">
        </Polyline>
    </Canvas>
    <TextBlock Height="55" Name="tb" Foreground="White" FontSize="{Binding Path=TS}" Text="JUST A TEST!" />
    <Button Content="Add Point" Height="23" HorizontalAlignment="Left" Margin="745,617,0,0" Name="Button1" VerticalAlignment="Top" Width="75" />
</Grid>

コードビハインドは次のとおりです。

Imports System.Windows
Imports System.Windows.Media
Imports System.Collections.ObjectModel

Partial Public Class MainPage
    Inherits UserControl

    Dim r As New Random(345)
    Private _punkte As New ObservableCollection(Of Point)
    Public Property Punkte As ObservableCollection(Of Point)
        Get
            Return _punkte
        End Get
        Set(value As ObservableCollection(Of Point))
            _punkte = value
            SetValue(Punkte_DP, _punkte)
        End Set
    End Property

    Private _ts As Integer
    Public Property TS As Integer
        Get
            Return _ts
        End Get
        Set(value As Integer)
            _ts = value
            SetValue(TS_DP, _ts)
        End Set
    End Property

    Public Punkte_DP As DependencyProperty = DependencyProperty.Register("Punkte", GetType(ObservableCollection(Of Point)), GetType(MainPage), New PropertyMetadata(New ObservableCollection(Of Point)))
    Public TS_DP As DependencyProperty = DependencyProperty.Register("TS", GetType(Integer), GetType(MainPage), New PropertyMetadata(New Integer))

    Public Sub New()

        Me.DataContext = Me
        InitializeComponent()

        Linie.DataContext = Me.Punkte
        Punkte.Add(New Point(100, 100))
        Punkte.Add(New Point(700, 300))

        TS = 25
    End Sub

    Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
        Punkte.Add(New Point(r.Next(0, 600), r.Next(0, 600)))
    End Sub
End Class

これを実行すると、FontSize が更新されますが、単一のポイントはありません。引かれる線。ボタンをクリックするたびにコレクションが大きくなりますが、何も起こりません。

ここで何が欠けているのですか?ご協力いただきありがとうございます!

よろしく、 ロブ

4

1 に答える 1

4

ポリゴン内のポイントが更新されない理由は、Polygon.Pointsプロパティが type の値を取り、 Silverlight がを自体PointCollectionに変換できないためです。ObservableCollection<Point>PointCollection

必要なのは、からに変換するコンバーターを追加することです。次のようなことを行う必要があります。ObservableCollection<Point>PointCollection

public class ObservableCollectionToPointCollectionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var points = value as ObservableCollection<Point>;
        if (points == null)
        {
            return null;
        }

        var collection = new PointCollection();
        foreach (Point point in points)
        {
            collection.Add(point);
        }

        return collection;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        // Not needed for one-way bindings.
        throw new NotImplementedException();
    }
}

演習として、これを VB.NET に変換するのはあなたに任せます。

このコンバーターを接続するには、次のような名前空間宣言を追加します。

xmlns:myns="clr-namespace:YourNamespaceContainingTheConverter"

ルート<UserControl>タグに追加

<UserControl.Resources>
    <myns:ObservableCollectionToPointCollectionConverter x:Key="converter" />
</UserControl.Resources>

このタグの終了後、前に、およびtoのバインディング<Grid>を変更しますPointsPolygon

Points="{Binding Punkte, Converter={StaticResource converter}}"

ただし、コードで発生した他のいくつかの問題がありました。

まず、最初にコードを実行したときに、「値が期待される範囲内にありません」というエラーがいくつか発生しました。これは、 TextBlock.FontSizeが正の値でなければならないことが原因であることが判明しました。TSへの割り当ての前にへの初期化を移動するMe.DataContextと、これらのエラーはなくなりました。

第二に、行Linie.DataContext = Me.Punkteが間違っています。これにより、 の DataContext が of に設定さPolygonれます。Polygon のプロパティのバインディングは、Silverlight に、データ コンテキストの名前の付いたプロパティ、つまり of のコレクションを探すように指示します。クラスには という名前のプロパティがないため、これは失敗します。この行は削除する必要があります。Polygon は、 という名前のプロパティを持つデータ コンテキストを親から継承します。ObservableCollectionPoint{Binding Punkte}PointsPunkteObservableCollectionPointObservableCollectionPunktePunkte

3 番目に、MainPage.xaml.vb の依存関係プロパティの使用を「通常の」CLR プロパティに置き換え、INotifyPropertyChangedMainPageを実装しました。プロパティは次のようになります。

    public ObservableCollection<Point> Punkte
    {
        get { return _punkte; }
        set
        {
            _punkte = value;
            FirePropertyChanged("Punkte");
        }
    }

    public double TS
    {
        get { return _ts; }
        set
        {
            _ts = value;
            FirePropertyChanged("TS");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

繰り返しますが、これを VB.NET に自由に変換してください。

最後に行った変更は、イベント ハンドラーFirePropertyChanged("Punkte")への呼び出しを追加することでした。Button1_Clickこれにより、Silverlight は、観測可能なポイントのコレクション (したがって、変換された PointCollection) が変更されたため、UI によって更新する必要があることを認識できます。

通常、ObservableCollectionビューモデルのコレクションに s を使用するだけで、変更通知を機能させることができます。ObservableCollectionただし、この場合、 が UI レイヤーに渡される前に別のオブジェクトに変換されるため、うまく機能しません。その結果、 によって発生したCollectionChangedイベントObservableCollectionはリッスンされません。これはコード自体の問題ではなく、フレームワークの制限です。PointCollectionも実装されている のサブクラスを作成できるかどうかを調べましたが、 でINotifyCollectionChangedあるため、これは不可能PointCollectionですsealed

のみに対してこのイベントを発生させる代わりに、クラスでのイベントAddを処理し、このイベント ハンドラで を呼び出す方がよい場合があります。そうすれば、ポリゴンはコレクションへのすべての変更を反映して最新の状態に保たれます。ObservableCollectionCollectionChangedMainPageFirePropertyChanged("Punkte")

于 2012-12-16T15:07:23.123 に答える