Graeme_Grant
Сила WPF над WinForms заключается в ряде областей, одной из которых является привязка данных[^]. Как только вы освоите привязку данных, вам не захочется работать непосредственно с элементами управления, так как это гораздо проще.
Итак, имея это в виду, Ниже приведено решение, которое демонстрирует, как работать с данными.
Привязка данных WPF использует систему уведомлений о том, когда данные изменяются. Для отдельных объектов/классов определяется с помощью INotifyPropertyChanged
интерфейс. Чтобы упростить реализацию, я использую следующий базовый класс:
public abstract class ObservableBase : INotifyPropertyChanged
{
public void Set<TValue>(ref TValue field, TValue newValue,
[CallerMemberName] string propertyName = "")
{
if (EqualityComparer<TValue>.Default
.Equals(field, default(TValue)) ||
!field.Equals(newValue))
{
field = newValue;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
1. Сначала нам нужно смоделировать данные:
public class UserMenuMapping : ObservableBase
{
private long userId;
public long UserId
{
get => userId;
set => Set(ref userId, value);
}
private int menuId;
public int MenuId
{
get => menuId;
set => Set(ref menuId, value);
}
private bool canEdit;
public bool CanEdit
{
get => canEdit;
set => Set(ref canEdit, value);
}
private bool canView;
public bool CanView
{
get => canView;
set => Set(ref canView, value);
}
public int Action()
{
if (!CanEdit && CanView) return 2;
else if (CanEdit && CanView) return 3;
else if (CanEdit && !CanView) return 1;
return 0;
}
}
2. Теперь нам нужно настроить данные в нашем коде позади.
Для коллекций объектов WPF имеет специальный класс коллекции списков, называемый
ObservableCollection
который реализует
INotifyCollectionChanged
&усилитель;
INotifyPropertyChanged
интерфейсы для привязки данных WPF.
public MainWindow()
{
InitializeComponent();
DataContext = this; // bind to code behind
MockData(); // Load the data to be displayed
}
private void MockData()
{
Data.Clear(); // always use clear not new to not break the binding
for (int i = 0; i < 10; i++)
{
Data.Add(new UserMenuMapping
{
UserId = 10000 + i,
MenuId = 10+i,
CanEdit = true,
CanView = true
});
}
}
public ObservableCollection<UserMenuMapping> Data { get; }
= new ObservableCollection<UserMenuMapping>();
private void Button_Click(object sender, RoutedEventArgs e)
{
foreach (var row in Data)
{
// Save to DB
Debug.WriteLine($"User:{row.UserId} | Menu:{row.MenuId} | Action: {row.Action()}");
}
}
}
Выше мы связываем XAML в код позади. Это будет подвергать
Data
коллекция
собственность к пользовательскому интерфейсу. Теперь мы можем связать
DataGrid
чтобы разрешить редактирование данных:
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DataGrid ItemsSource="{Binding Data}"
GridLinesVisibility="None"
AlternatingRowBackground="GhostWhite" AlternationCount="1"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
AutoGenerateColumns="False"
RowDetailsVisibilityMode="VisibleWhenSelected"
VirtualizingPanel.ScrollUnit="Pixel">
<DataGrid.Columns>
<DataGridTextColumn Header="User ID" Binding="{Binding UserId}"/>
<DataGridTextColumn Header="Menu ID" Binding="{Binding MenuId}"/>
<DataGridCheckBoxColumn Header="Can Edit" Binding="{Binding CanEdit}"/>
<DataGridCheckBoxColumn Header="Can View" Binding="{Binding CanView}"/>
</DataGrid.Columns>
</DataGrid>
<Button Content="SAVE" Grid.Row="1"
Click="Button_Click"
HorizontalAlignment="Center"
Padding="10 5" Margin="10"/>
</Grid>
Как вы можете видеть в
Button_Click
вам не нужно делать ничего особенного, чтобы прочитать назад какие-либо изменения.