开发者

Get INotifyPropertyChanged on multiple inherited objects

Well, i don't think my title is quite efficient, but anyway. Let me explain more precisely.

I have a class, Vehicle. I created two child classes, Car and Plane. I want to monitor the speed, which is a Vehicle Property, and bind it to a control (label, or image, for example) in WPF. When i create a static Class which only purpose is watching the Speed Property, it works, as far as the INotifyPropertyChanged is declared with the Speed Property name.

But the problem is, I have to create dynamicly multiple Cars and Planes by looking in an XML file and deserializing my objects, and creating multiple Car or Plane UserControl (Let's not discuss this way of working, please). So I have to get the Speed property inside the Vehicle Class (which is normal), and I have to get a INotifyPropertyChanged on each Speed of each Vehicle Created. So, my Cars and Planes are loaded, and I have to get all speeds, but I can't create a static Speed property by Vehicle. By the way, by creating a non-static Speed property (as int, for example) in Vehicle Class with INotifyPropertyChanged raised in the setter, it does not work. The event seems to be raised, but my converter is not fired, and my controls does not update.

In my Vehicle Class

Private SpeedValue As Integer
<XmlIgnore()>
Public Property Speed() As Short
    Get
        Return SpeedValue 
    End Get
    Set(ByVal value As Short)
        SpeedValue = value
        NotifyPropertyChanged("Speed")
    End Set
End Property

Public Event PropertyChanged As PropertyChangedEventHandler _
    Implements INotifyPropertyChanged.PropertyChanged

Private Sub NotifyPropertyChanged(ByVal info As String)
    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))

End Sub

In my codebehind

Dim b As Binding = New Binding()
    b.Source = theVehicle
    b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
    b.Path = New PropertyPath(theVehicle.Speed)
    b.Path = New PropertyPath("Speed")
    b.Converter = New SpeedValueToPicturePathConverter()
    b.ConverterPa开发者_运维问答rameter = GetType(Vehicle)
    img_fonctionnement.SetBinding(Image.SourceProperty, b)

I tried with lambda expressions, also, but i couldn't figure out how to make the whole thing work. I also had an "an item with the same key has already been added" error, but I so changed my code that I cannot remember how. I know my explaination is bad, but it is pretty hard to explain (and I'm French ;)). Please, if you could help me, it would be nice, because I'm a bit stuck here.

UPDATE

More code :

This is in my WatchTower Thread, which execute every 10 secondes. All this code here works

' theConfig is a singleton which represent my XML config file deserialized
' Getting all vehicles declared in this file works by doing this
For Each vehic As Vehicle In theConfig.Vehicles
        Dim realTimeSpeed = server.Read("speed") 'reading the speed on some distant server - don't discuss this, it works fine
        If (Not vehic.Speed = realTimeSpeed) Then
            vehic.Speed = realTimeSpeed
        End If

    Next

This is where I add a TabItem for each Vehicle declared in the theConfig XML file

'This actually works, a tab is added for each vehicle
For Each vehic As Vehicle In theConfig.Vehicles
        Dim vehicTabItem As TabItem = New TabItem()
        vehicTabItem.Header = vehic.Description
        If (TypeOf vehic Is Car) Then
        'Adding the CarView UserControl of my own
            vehicTabItem.Content = New CarView(DirectCast(vehic, Car))
            TabControl1.Items.Add(vehicTabItem)
        ElseIf (TypeOf vehic Is Plane) Then
            vehicTabItem.Content = New PlaneView(DirectCast(vehic, Plane))
            TabControl1.Items.Add(vehicTabItem)

        End If

    Next

This is inside a CarView file (WPF usercontrol, codebehind)

Public Class CarView

Private theCar As Car

Public Sub New(ByVal theCar As Car)

    InitializeComponent()

    Me.theCar = theCar 

    Dim b As Binding = New Binding("Speed")
    b.Source = theCar
    b.Converter = New SpeedValueToPicturePathConverter()
    b.ConverterParameter = GetType(Vehicle)
    'img_fonctionnement is created in the graphic designer in Visual Studio in xaml
    'Remember, this binding works whn I use a static property just for testing
    img_fonctionnement.SetBinding(Image.SourceProperty, b)

End Sub

The PlaneView Class is almost the same for this part.

I confirm that the converter is fired just once, the first time, when the tabs are created, because I put a breakpoint on the Convert function definition. After that, the converter is never fired again. So the picture img_fonctionnement is displayed, but it is never updated. But the Speed property is updated, I swear. And the INotifyPropertyChanged (in Speed's setter) is raised, as far as i know with the help of the debugger.

And the "an item with the same key has already been added" (which appears in a messageBox, and not as an exception) seems to appear only when I am to long with the debugger. In normal execution mode, it never shows.


I don't understand the code you are using to create the binding.

It should be as simple as that:

Dim b As Binding = New Binding("Speed")
b.Source = theVehicle
b.Converter = New SpeedValueToPicturePathConverter()
b.ConverterParameter = GetType(Vehicle)
img_fonctionnement.SetBinding(Image.SourceProperty, b)

If this doesn't help, there might be other problems:

  • Is theVehicle really the correct instance?
  • Is the speed of that instance really updated?


My bad. I was refreshing a Vehicle Collection, but I was creating my tabs with another independent Vehicle Collection (base on the same XML File). I created a singleton, but i wasn't using it everywhere.

I am so bad.

Thanks, Daniel, you helped me anyway, even if your answer wasn't the cause of my problem ;)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜