【问题标题】:Silverlight - Binding issue when using inheritenceSilverlight - 使用继承时的绑定问题
【发布时间】:2012-08-12 04:53:15
【问题描述】:

我使用的是 Esri 的地图,它提供了一个可以将集合绑定到地图的功能,它可以为绘制和渲染图形点提供所有魔法。它只要求对象具有一些要绑定的属性,如下所示:

<esri:PointDataSource
         ItemsSource="{Binding Path=PlottedData, Source={StaticResource ViewModel}, Mode=TwoWay}"
         XCoordinateBinding="{Binding X}"
         YCoordinateBinding="{Binding Y}"
         IsSelectedBinding="{Binding IsSelected, Mode=TwoWay}">

当然,我的应用程序需要的数据不仅仅是这些点,而且还有不同的类型。这导致我们为所有不同类型创建 DataPoint 的子类,然后将它们传递给地图,这样地图就不会更明智了。

我在没有子类的演示应用程序中很好地工作,但是当我将它合并到应用程序中并开始从服务作为子类接收数据时,IsSelected 功能停止工作。我可以确认所有点上的 IsSelected 属性正在按预期切换,但是当我切换它们时,它们不会反射回地图上。澄清一下,如果我将服务结果替换为 在它们返回模型之后

var returned = new ObservableCollection<DataPoint>()
    {
        new DataPoint(){IsPlottable = true, IsSelected = false, X = 722762, Y = 488253},
        new DataPoint(){IsSelected = false, X = 810000, Y = 550000, IsPlottable = true},
        new DataPoint(){IsSelected = false, X = 801000, Y = 480000, IsPlottable = true},
        new DataPoint(){IsSelected = false, X = 800100, Y = 500000, IsPlottable = true},
        new DataPoint(){IsSelected = false, X = 800010, Y = 506000, IsPlottable = true}
    };

然后就可以了。然后我用这个替换它:

var returned = new ObservableCollection<DataPoint>()
    {
        new DataPointSubclass(){IsPlottable = true, IsSelected = false, X = 722762, Y = 488253},
        new DataPointSubclass(){IsSelected = false, X = 810000, Y = 550000, IsPlottable = true},
        new DataPointSubclass(){IsSelected = true, X = 801000, Y = 480000, IsPlottable = true},
        new DataPointSubclass(){IsSelected = false, X = 800100, Y = 500000, IsPlottable = true},
        new DataPointSubclass(){IsSelected = true, X = 800010, Y = 506000, IsPlottable = true}
    };

它停止工作。同时,这些点被正确绘制——所以我知道至少在创建绑定集合时绑定正在工作(注意上面的子类如何有一些 IsSelected = true;最初也绑定正确)。

我的继承实现可能会导致绑定从基本上从单向/双向绑定切换到一次性绑定?我会不会错误地归咎于问题?

编辑:感谢下面的 cmets,我将其范围缩小到 PropertyChange 事件处理程序在设置 IsSelected 时为空。为清楚起见,这里是我在基类中定义 IsSelected 的公共成员的地方:

    [DataMember]
    public bool IsSelected
    {
        get { return _IsSelected; }
        set
        {
            if (_IsSelected != value)
            {
                _IsSelected = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
            }
        }
    }

在我的演示应用程序中,一切正常,如果我使用上面的第一组虚拟点(有效),PropertyChanged 不为空,并且 setter 引发 PropertyChanged 事件。

但是,当使用 DataPointSubclass 时,PropertyChanged 始终为 null(但正在触发 setter)。我会在这里遗漏什么?

【问题讨论】:

  • 您已将子类集合声明为 ObservableCollection&lt;DataPoint&gt; 而不是 ObservableCollection&lt;DataPointSubclass&gt;。这是故意的吗?
  • 我不知道您在这个新子类中创建了哪些属性,但您是否使用 INotifyPropertyChanged 进行了这些属性。
  • @ChrisF 这不是故意的,但我已经检查过了,没有任何区别。感谢您指出了这一点。在我的应用程序中进行调试,在它只处理 DataPoint 的区域中,我可以查看该对象,它仍然标识为 DataPointSubclass,这是我所期望的。我可能会从 CS101 中忘记这种继承吗?
  • @Nathan - 我不这么认为 :) 我只是在检查您的示例中的代码错误是否无意中引入了不同的问题。
  • @Justin 我想你中了大奖。我没有在子类中的任何属性上实现 INotifyPC,因为它们应该只是只读的。 IsSelected 不会被 DataPoint 覆盖,所以我只使用 DataPoint 中的属性,它确实在预期的地方实现了 INotifyPropertyChanged。我注意到但由于某些天真的原因被忽略的有趣的事情是,在集成应用程序中(与我的演示应用程序相反),当我切换 IsSelected 属性时,PropertyChanged 在 DataPoint.IsSelected 的设置器中为空,所以我从不引发 PropertyChanged 事件。

标签: c# wpf silverlight binding esri


【解决方案1】:

您的服务代码有ObservableCollection&lt;DataPoint&gt;(),所以我猜该方法的返回类型是IQueryable&lt;DataPoint&gt;IEnumerable&lt;DataPoint&gt;

这样做只是序列化它知道的位(即DataPoint)并忽略其他成员。

您需要将预期类型更改为派生类才能正确序列化。

【讨论】:

  • 我没有想到,但这并没有解决问题。我将编辑我的帖子以使其更清楚:在模型接收(并忽略)来自数据库的数据之后,在模型中创建人为的 ObservableCollections ——即,即使我根本不使用序列化数据,也会出现这个问题。该服务返回一个 IEnumerable(DataPointSubclass)。
【解决方案2】:

这是我的工具妨碍的情况之一。

我有一个实现 INotifyPropertyChanged 服务器端的基类。我的服务返回一个对象集合,这些对象是它的子类。由于它是一个子类,我的客户需要访问基类。为了解决这个问题,我添加了一个真正存在于服务器端的文件客户端作为链接。这样,当我更新服务引用时,会在客户端(在references.cs 中)生成一个部分类,看起来有点像这样:

public partial class DataPointSubclass: Application.Server.Data.SharedCode.DataPoint, INotifyPropertyChanged { }

这是一个非常酷的功能,除了它实现了 INotifyPropertyChanged,尽管 DataPoint 也实现了它。这是一个很大的禁忌,是我所有问题的根源。 当您在子类上重新实现 INPC(至少不覆盖基类的属性)时,PropertyChanged 在基类中将始终为 null。在这种情况下,服务引用自动实现了 INotifyPropertyChanged,而不检查其基类是否已经实现。

解决方案:您必须在 References.svcmap 中禁用此功能。查找此属性并将其设置为 false

<EnableDataBinding>true</EnableDataBinding>

您可以通过在解决方案资源管理器中显示所有文件并查看您的服务器引用树来找到 References.svcmap。

通过这样做,通过更新服务引用自动生成的类不会自动实现 INotifyPropertyChanged。如果您想拥有该功能,您可能必须手动实现它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-07-20
    • 1970-01-01
    • 1970-01-01
    • 2011-07-19
    相关资源
    最近更新 更多