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 的值PointCollection,并且 Silverlight 无法将 a 转换ObservableCollection<Point>为 aPointCollection本身。

您需要做的是添加一个从转换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>

在此标记结束之后但之前<Grid>,并修改Points您的绑定Polygon

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

但是,我在使用您的代码时遇到了其他一些问题。

首先,当我第一次运行您的代码时,出现了一些“值不在预期范围内”的错误。原来这是因为TextBlock.FontSize必须有一个正值。TS我在分配到之前将初始化移动到Me.DataContext并且这些错误消失了。

其次,线路Linie.DataContext = Me.Punkte错了。这会将 的 DataContext 设置Polygon为您ObservableCollectionPoints。{Binding Punkte}Polygon 属性中的绑定Points告诉Silverlight 在以Punkte数据上下文命名的属性(即sObservableCollection的属性)中查找集合。Point这将失败,因为ObservableCollection该类没有名为 的属性PunktePunkte此行应该被删除 - Polygon 将从其父级继承其数据上下文,该数据上下文确实具有名为 的属性。

第三,我用“普通”CLR 属性替换了您在 MainPage.xaml.vb 中使用的依赖属性,并MainPage实现了INotifyPropertyChanged。然后属性如下所示:

    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,但这是不可能的,因为PointCollectionis sealed

与其只为Adds 触发此事件,不如在您的类中处理ObservableCollection'事件,并让此事件处理程序调用。这样,多边形将与集合的所有更改保持同步。CollectionChangedMainPageFirePropertyChanged("Punkte")

于 2012-12-16T15:07:23.123 回答