Привязка WPF ComboBox не работает должным образом

Я хочу, чтобы свойство ItemsSource моего WPF ComboBox было привязано к свойству MyListObject MyList. Проблема в том, что когда я обновляю свойство MyList в коде, WPF ComboBox не отражает обновление. Я вызываю событие PropertyChanged после выполнения обновления и думал, что WPF должен был автоматически ответить обновлением пользовательского интерфейса. Я что-то упускаю?

Вот объект CLR:

Imports System.ComponentModel

Public Class MyListObject
    Implements INotifyPropertyChanged

    Private _mylist As New List(Of String)

    Public Sub New()
        _mylist.Add("Joe")
        _mylist.Add("Steve")
    End Sub

    Public Property MyList() As List(Of String)
        Get
            Return _mylist
        End Get
        Set(ByVal value As List(Of String))
            _mylist = value
        End Set
    End Property

    Public Sub AddName(ByVal name As String)

        _mylist.Add(name)

        NotifyPropertyChanged("MyList")

    End Sub

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

    Public Event PropertyChanged(ByVal sender As Object, _
            ByVal e As System.ComponentModel.PropertyChangedEventArgs) _
            Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

End Class

Вот XAML:

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    xmlns:local="clr-namespace:WpfApplication1"
        >

    <Window.Resources>
        <ObjectDataProvider x:Key="MyListObject" ObjectType="{x:Type local:MyListObject}"/>
    </Window.Resources>

        <Grid>

        <ComboBox Height="23"
                  Margin="24,91,53,0"
                  Name="ComboBox1"
                  VerticalAlignment="Top" 
                  ItemsSource="{Binding Path=MyList, Source={StaticResource MyListObject}}"
                  />
        <TextBox Height="23"
                 Margin="24,43,134,0"
                 Name="TextBox1"
                 VerticalAlignment="Top" />
        <Button Height="23"
                HorizontalAlignment="Right"
                Margin="0,43,53,0"
                Name="btn_AddName"
                VerticalAlignment="Top"
                Width="75">Add</Button>
    </Grid>
</Window>

А вот простой код программной части:

Class Window1 

    Private obj As New MyListObject

    Private Sub btn_AddName_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) _ 
    Handles btn_AddName.Click

        obj.AddName(TextBox1.Text)

    End Sub
End Class

Спасибо!


person Rob Sobers    schedule 27.10.2008    source источник


Ответы (3)


Вы привязываетесь к списку строк. Этот класс списка не реализует свойство Inotify. Вместо этого вы должны использовать наблюдаемую коллекцию. Я также замечаю, что в вашем коде вы объявляете

Private obj As New MyListObject

Это не статический ресурс, к которому вы привязали поле со списком. Таким образом, ваш вызов добавления не будет отражен в вашем представлении.

person Aaron Fischer    schedule 27.10.2008
comment
Не похоже, что изменение свойства на ObservableCollection каким-либо образом влияет на обновление источника элементов поля со списком. - person Rob Sobers; 27.10.2008

ObservableCollection, скорее всего, является решением, но если он все еще огорчает вас, вы можете напрямую получить доступ к своему статическому ресурсу, вызвав следующий код после обновления вашего списка:

DirectCast(Me.FindResource("MyListObject"), ObjectDataProvider).Source = _myList
person Dillie-O    schedule 27.10.2008
comment
Мне также интересно, улучшит ли ситуацию изменение вашего ObjectDataProvider на CollectionViewSource. - person Dillie-O; 27.10.2008

Попробуйте использовать BindingList (Of T) вместо списка (Of Т).

Изменить: я новичок в WPF, и похоже, что BindingList не является полным решением вашей проблемы, но может быть шагом в правильном направлении. Мне удалось протестировать MyListObject, преобразованный в BindingList в WinForm, и событие ListChanged было вызвано в ComboBox, который затем обновил свой список.

Я нашел это (возможное) решение для обертывания вашего класса в ObservableCollection, которое может помочь вам решить вашу проблему.

Включение WPF Magic с помощью WCF - часть 1

Это код для обновления вашего объекта до BindingList. Объедините свой код с кодом из этого ресурса, и все будет в порядке.

Public Class MyListObject
    ...

    'Private _mylist As New List(Of String)
    Private _mylist As New BindingList(Of String)

    ...

    'Public Property MyList() As List(Of String)
    '    Get
    '        Return _mylist
    '    End Get
    '    Set(ByVal value As List(Of String))
    '        _mylist = value
    '    End Set
    'End Property

    Public Property MyList() As BindingList(Of String)
        Get
            Return _mylist
        End Get
        Set(ByVal value As BindingList(Of String))
            _mylist = value
        End Set
    End Property

    ...

End Class
person Chris Porter    schedule 27.10.2008
comment
Список привязки не реализует INotifyCollectionChanged или INotifyPropertyChanged, что и ищет wpf. - person Aaron Fischer; 27.10.2008
comment
BindingList поддерживает старое уведомление об изменении, которое WPF все еще уважает. Кроме того, BindingList будет активировать уведомление об изменении при изменении любого из дочерних объектов (в отличие от ObservableCollection). Кроме того, BindingList - это IList, что приятно, потому что у него есть возможность LINQ, например .ForEach. - person Nate Zaugg; 28.04.2010