Graeme_Grant
Сообщение об ошибке является лучшим индикатором того, что требуется.
Привязка данных WPF[^] намного превосходит и проще систему привязки данных WinForm. Как только вы потратите время на изучение того, как привязка данных работает в WPF, вам не захочется оглядываться назад.
Вот пример, который быстро покажет вам, как работает привязка данных:
Привязка WPF для обновления свойств требует PropertyChanged
событие, которое будет запущено для каждого свойства. Для коллекций мы можем использовать специализированный класс коллекций, называемый ObservableCollection
который стреляет а CollectionChanged
событие.
Для свойств ниже приведен базовый класс, упрощающий повторяющийся код, необходимый для каждого свойства в классе:
Public MustInherit Class ObservableBase
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler _
Implements INotifyPropertyChanged.PropertyChanged
Public Sub [Set](Of TValue)(ByRef field As TValue, ByVal newValue As TValue,
<CallerMemberName> ByVal Optional propertyName As String = "")
If EqualityComparer(Of TValue).[Default].Equals(field, Nothing) OrElse Not field.Equals(newValue) Then
field = newValue
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End If
End Sub
End Class
Для этого примера я буду использовать
PersonModel
класс, который наследует
ObservableBase
базовый класс выше:
Public Class PersonModel
Inherits ObservableBase
Private mName As String
Public Property Name As String
Get
Return mName
End Get
Set(ByVal value As String)
[Set](mName, value)
End Set
End Property
Private mAge As Integer
Public Property Age As Integer
Get
Return mAge
End Get
Set(ByVal value As Integer)
[Set](mAge, value)
End Set
End Property
End Class
Теперь мы можем создать нашу коллекцию и добавить
событие для демонстрации системы привязки в действии:
Imports System.Collections.ObjectModel
Class MainWindow
Public Sub New()
InitializeComponent()
DataContext = Me
Mock()
End Sub
Public Property Persons As ObservableCollection(Of PersonModel) = New ObservableCollection(Of PersonModel)()
Private rand As Random = New Random()
Private Sub Mock()
For i As Integer = 0 To 10 - 1
Persons.Add(New PersonModel With {
.Name = String.Format("Person {0}", i),
.Age = rand.[Next](20, 50)
})
Next
End Sub
Private Sub Button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
For Each person In Persons
person.Age = rand.[Next](20, 50)
Next
End Sub
End Class
На приведенной выше странице с кодовым кодом я установил форму
DataContext
к самой кодовой странице. Это позволит пользовательскому интерфейсу (XAML) видеть уведомления о привязке и обновлять отображение.
Наконец, мы можем
связывать то
свойства из кода-позади к элементам пользовательского интерфейса:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfSimpleBindingVB"
Title="MainWindow"
WindowStartupLocation="CenterScreen" Height="400" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:PersonModel}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Margin="10 3"/>
<TextBlock Text="{Binding Age}" Margin="10 3"
Grid.Column="1"/>
</Grid>
</DataTemplate>
</Grid.Resources>
<ListBox ItemsSource="{Binding Persons}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<Button Content="Randomize" Padding="10 5" Margin="10"
HorizontalAlignment="Center" VerticalAlignment="Center"
Grid.Row="1" Click="Button_Click"/>
</Grid>
</Window>
В приведенном выше примере используется элемент управления ListBox. Принципы для ListView точно такие же. Вот пользовательский интерфейс, использующий вместо этого ListView:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfSimpleBindingVB"
Title="MainWindow"
WindowStartupLocation="CenterScreen" Height="400" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListView ItemsSource="{Binding Persons}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
<GridViewColumn Header="Age" DisplayMemberBinding="{Binding Age}" />
</GridView>
</ListView.View>
</ListView>
<Button Content="Randomize" Padding="10 5" Margin="10"
HorizontalAlignment="Center" VerticalAlignment="Center"
Grid.Row="1" Click="Button_Click"/>
</Grid>
</Window>
В этом примере используется тот же метод привязки данных, что и в шаблоне проектирования MVVM (Model View ViewModel), за исключением того, что ViewModel находится в коде позади него. MVVM немного более вовлечен и выходит за рамки этого ответа, но стоит потратить время на обучение.
Graeme_Grant
Привет Майк,
Он фактически отвечает на ваш вопрос и следующий, который вы зададите, когда измените данные свойства.
С помощью WPF вы работаете с данными, и пользовательский интерфейс будет отражать изменения. Ваш код работает непосредственно с элементами управления, а не с данными. Когда вы работаете с данными, это намного проще и не связано с конкретными элементами управления. Вышеприведенное решение демонстрирует это.
Но чтобы ответить на ваш конкретный вопрос, чтобы добавить новую запись, вы просто создаете новый класс записей и добавляете его в класс записей. ObservableCollection
и пользовательский интерфейс будет отражать это изменение - в этом случае будет добавлена новая строка:
Persons.Add(New PersonModel With {
.Name = String.Format("Person {0}", i),
.Age = rand.[Next](20, 50)
})