C# 数据网格与自定义对象绑定
C# data grid binding with custom objects
我正在尝试在 DataGrid 中显示帐户数据,但绑定似乎无法正常工作。
public ObservableCollection<AccountData> accountlist = new ObservableCollection<AccountData>();
public MainWindow()
{
InitializeComponent();
AccountDataGrid.ItemsSource = accountlist;
}
这是我的列表的样子以及我如何将它绑定到数据网格。
GetAccountsResponse resp = GetAccountsResponse.GetAccounts(m_authImpl);
List<AccountData> accounts = resp.Accounts;
for (int i = 0; i < accounts.Count; ++i)
{
AccountData account = accounts[i];
accountlist.Add(account);
}
我正在使用 API 获取帐户数据,然后将其放入我的可观察帐户列表中
<DataGrid x:Name="AccountDataGrid" HorizontalAlignment="Left" Height="249" Margin="10,278,0,0" VerticalAlignment="Top" Width="772" AutoGenerateColumns="False" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Path=m_type}"/>
<DataGridTextColumn Header="Number" Binding="{Binding Path=m_number}"/>
<DataGridTextColumn Header="Status" Binding="{Binding Path=m_status}"/>
<DataGridTextColumn Header="isPrimary" Binding="{Binding Path=m_isPrimary}"/>
<DataGridTextColumn Header="isBilling" Binding="{Binding Path=m_isBilling}"/>
<DataGridTextColumn Header="clientAccountType" Binding="{Binding Path=m_clientAccountType}"/>
</DataGrid.Columns>
</DataGrid>
这是我的数据网格的代码
public class AccountData
{
public UserAccountType m_type;
public string m_number;
public AccountStatus m_status;
public bool m_isPrimary;
public bool m_isBilling;
public ClientAccountType m_clientAccountType;
public AccountData();
}
这就是我的对象的样子!
一些背景故事:
accountlist 在调试器中具有所有正确的信息,但是当需要在数据网格中显示结果时,它显示为空白条目。
public enum UserAccountType
{
Undefined = 0,
Cash = 1,
Margin = 2,
TFSA = 3,
RRSP = 4,
SRRSP = 5,
LRRSP = 6,
LIRA = 7,
LIF = 8,
RIF = 9,
SRIF = 10,
LRIF = 11,
RRIF = 12,
PRIF = 13,
RESP = 14,
FRESP = 15,
FX = 16,
FXD = 17,
Count = 18
}
public enum AccountStatus
{
Undefined = -1,
UnAllocated = 0,
Active = 1,
SuspendedClosed = 2,
SuspendedViewOnly = 3,
LiquidateOnly = 4,
Closed = 5,
Count = 6
}
public enum ClientAccountType
{
Undefined = 0,
Individual = 1,
Joint = 2,
InformalTrust = 3,
Corporation = 4,
InvestmentClub = 5,
FormalTrust = 6,
Partnership = 7,
SoleProprietorship = 8,
Family = 9,
JointAndInformalTrust = 10,
Institution = 11,
Count = 12
}
WPF 绑定不支持字段,原因很明显(违反封装)
克服此问题的最简单方法是将 public 字段转换为属性。
public class AccountData
{
public UserAccountType m_type { get; set; }
public string m_number { get; set; }
public AccountStatus m_status { get; set; }
public bool m_isPrimary { get; set; }
public bool m_isBilling { get; set; }
public ClientAccountType m_clientAccountType { get; set; }
public AccountData() { /* . . . */ }
}
让我们使用 MVVM 来完成。该方法的主要目标是:对数据所做的任何更改都会立即实时显示在 DataGrid
中。
你需要一个实现INotifyPropertyChanged
接口
的助手class
NotifyPropertyChanged.cs
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
然后使新数据class 派生自NotifyPropertyChanged
。为了与 AccountData
class 兼容,我为带有 AccountData
参数的构造函数添加了一个重载。
UIAccountData.cs
public class UIAccountData : NotifyPropertyChanged
{
private UserAccountType m_type;
private string m_number;
private AccountStatus m_status;
private bool m_isPrimary;
private bool m_isBilling;
private ClientAccountType m_clientAccountType;
public UserAccountType Type
{
get => m_type;
set
{
m_type = value;
OnPropertyChanged();
}
}
public string Number
{
get => m_number;
set
{
m_number = value;
OnPropertyChanged();
}
}
public AccountStatus Status
{
get => m_status;
set
{
m_status = value;
OnPropertyChanged();
}
}
public bool IsPrimary
{
get => m_isPrimary;
set
{
m_isPrimary = value;
OnPropertyChanged();
}
}
public bool IsBilling
{
get => m_isBilling;
set
{
m_isBilling = value;
OnPropertyChanged();
}
}
public ClientAccountType ClientAccountType
{
get => m_clientAccountType;
set
{
m_clientAccountType = value;
OnPropertyChanged();
}
}
public UIAccountData() { }
public UIAccountData(AccountData account)
{
m_type = account.m_type;
m_number = account.m_number;
m_status = account.m_status;
m_isPrimary = account.m_isPrimary;
m_isBilling = account.m_isBilling;
m_clientAccountType = account.m_clientAccountType;
}
public AccountData ToAccountData => new AccountData
{
m_type = m_type,
m_number = m_number,
m_status = m_status,
m_isPrimary = m_isPrimary,
m_isBilling = m_isBilling,
m_clientAccountType = m_clientAccountType,
};
}
然后创建包含集合并用于绑定的主要 class。
MainViewModel.cs
public class MainViewModel : NotifyPropertyChanged
{
public ObservableCollection<UIAccountData> _accountlist;
public ObservableCollection<UIAccountData> Accountlist
{
get => _accountlist;
set
{
_accountlist = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
// demo values
Accountlist = new ObservableCollection<UIAccountData>
{
new UIAccountData { Type = UserAccountType.Cash, Number = "123", Status = AccountStatus.Active, IsPrimary = true, IsBilling = true, ClientAccountType = ClientAccountType.Individual },
new UIAccountData { Type = UserAccountType.Margin, Number = "aaa", Status = AccountStatus.Active, IsPrimary = false, IsBilling = true, ClientAccountType = ClientAccountType.InformalTrust },
new UIAccountData { Type = UserAccountType.LRRSP, Number = "bbb", Status = AccountStatus.SuspendedClosed, IsPrimary = true, IsBilling = false, ClientAccountType = ClientAccountType.Partnership },
new UIAccountData { Type = UserAccountType.SRIF, Number = "456", Status = AccountStatus.SuspendedViewOnly, IsPrimary = false, IsBilling = false, ClientAccountType = ClientAccountType.Institution },
};
AccountData account = new AccountData() { m_type = UserAccountType.FX, m_number = "fff", m_status = AccountStatus.SuspendedViewOnly, m_isPrimary = true, m_isBilling = false, m_clientAccountType = ClientAccountType.Institution };
Accountlist.Add(new UIAccountData(account));
}
}
完整标记
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
Title="MainWindow" Height="600" Width="1000" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainViewModel/><!-- MainViewModel attached here -->
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Accountlist}" HorizontalAlignment="Left" AutoGenerateColumns="False" IsReadOnly="True" Width="Auto">
<DataGrid.Columns>
<DataGridTextColumn Width="*" Header="Type" Binding="{Binding Type}"/>
<DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number}"/>
<DataGridTextColumn Width="*" Header="Status" Binding="{Binding Status}"/>
<DataGridCheckBoxColumn Width="*" Header="IsPrimary" Binding="{Binding IsPrimary}"/>
<DataGridCheckBoxColumn Width="*" Header="IsBilling" Binding="{Binding IsBilling}"/>
<DataGridTextColumn Width="*" Header="ClientAccountType" Binding="{Binding ClientAccountType}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
最后
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
我正在尝试在 DataGrid 中显示帐户数据,但绑定似乎无法正常工作。
public ObservableCollection<AccountData> accountlist = new ObservableCollection<AccountData>();
public MainWindow()
{
InitializeComponent();
AccountDataGrid.ItemsSource = accountlist;
}
这是我的列表的样子以及我如何将它绑定到数据网格。
GetAccountsResponse resp = GetAccountsResponse.GetAccounts(m_authImpl);
List<AccountData> accounts = resp.Accounts;
for (int i = 0; i < accounts.Count; ++i)
{
AccountData account = accounts[i];
accountlist.Add(account);
}
我正在使用 API 获取帐户数据,然后将其放入我的可观察帐户列表中
<DataGrid x:Name="AccountDataGrid" HorizontalAlignment="Left" Height="249" Margin="10,278,0,0" VerticalAlignment="Top" Width="772" AutoGenerateColumns="False" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Type" Binding="{Binding Path=m_type}"/>
<DataGridTextColumn Header="Number" Binding="{Binding Path=m_number}"/>
<DataGridTextColumn Header="Status" Binding="{Binding Path=m_status}"/>
<DataGridTextColumn Header="isPrimary" Binding="{Binding Path=m_isPrimary}"/>
<DataGridTextColumn Header="isBilling" Binding="{Binding Path=m_isBilling}"/>
<DataGridTextColumn Header="clientAccountType" Binding="{Binding Path=m_clientAccountType}"/>
</DataGrid.Columns>
</DataGrid>
这是我的数据网格的代码
public class AccountData
{
public UserAccountType m_type;
public string m_number;
public AccountStatus m_status;
public bool m_isPrimary;
public bool m_isBilling;
public ClientAccountType m_clientAccountType;
public AccountData();
}
这就是我的对象的样子!
一些背景故事: accountlist 在调试器中具有所有正确的信息,但是当需要在数据网格中显示结果时,它显示为空白条目。
public enum UserAccountType
{
Undefined = 0,
Cash = 1,
Margin = 2,
TFSA = 3,
RRSP = 4,
SRRSP = 5,
LRRSP = 6,
LIRA = 7,
LIF = 8,
RIF = 9,
SRIF = 10,
LRIF = 11,
RRIF = 12,
PRIF = 13,
RESP = 14,
FRESP = 15,
FX = 16,
FXD = 17,
Count = 18
}
public enum AccountStatus
{
Undefined = -1,
UnAllocated = 0,
Active = 1,
SuspendedClosed = 2,
SuspendedViewOnly = 3,
LiquidateOnly = 4,
Closed = 5,
Count = 6
}
public enum ClientAccountType
{
Undefined = 0,
Individual = 1,
Joint = 2,
InformalTrust = 3,
Corporation = 4,
InvestmentClub = 5,
FormalTrust = 6,
Partnership = 7,
SoleProprietorship = 8,
Family = 9,
JointAndInformalTrust = 10,
Institution = 11,
Count = 12
}
WPF 绑定不支持字段,原因很明显(违反封装)
克服此问题的最简单方法是将 public 字段转换为属性。
public class AccountData
{
public UserAccountType m_type { get; set; }
public string m_number { get; set; }
public AccountStatus m_status { get; set; }
public bool m_isPrimary { get; set; }
public bool m_isBilling { get; set; }
public ClientAccountType m_clientAccountType { get; set; }
public AccountData() { /* . . . */ }
}
让我们使用 MVVM 来完成。该方法的主要目标是:对数据所做的任何更改都会立即实时显示在 DataGrid
中。
你需要一个实现INotifyPropertyChanged
接口
NotifyPropertyChanged.cs
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
然后使新数据class 派生自NotifyPropertyChanged
。为了与 AccountData
class 兼容,我为带有 AccountData
参数的构造函数添加了一个重载。
UIAccountData.cs
public class UIAccountData : NotifyPropertyChanged
{
private UserAccountType m_type;
private string m_number;
private AccountStatus m_status;
private bool m_isPrimary;
private bool m_isBilling;
private ClientAccountType m_clientAccountType;
public UserAccountType Type
{
get => m_type;
set
{
m_type = value;
OnPropertyChanged();
}
}
public string Number
{
get => m_number;
set
{
m_number = value;
OnPropertyChanged();
}
}
public AccountStatus Status
{
get => m_status;
set
{
m_status = value;
OnPropertyChanged();
}
}
public bool IsPrimary
{
get => m_isPrimary;
set
{
m_isPrimary = value;
OnPropertyChanged();
}
}
public bool IsBilling
{
get => m_isBilling;
set
{
m_isBilling = value;
OnPropertyChanged();
}
}
public ClientAccountType ClientAccountType
{
get => m_clientAccountType;
set
{
m_clientAccountType = value;
OnPropertyChanged();
}
}
public UIAccountData() { }
public UIAccountData(AccountData account)
{
m_type = account.m_type;
m_number = account.m_number;
m_status = account.m_status;
m_isPrimary = account.m_isPrimary;
m_isBilling = account.m_isBilling;
m_clientAccountType = account.m_clientAccountType;
}
public AccountData ToAccountData => new AccountData
{
m_type = m_type,
m_number = m_number,
m_status = m_status,
m_isPrimary = m_isPrimary,
m_isBilling = m_isBilling,
m_clientAccountType = m_clientAccountType,
};
}
然后创建包含集合并用于绑定的主要 class。
MainViewModel.cs
public class MainViewModel : NotifyPropertyChanged
{
public ObservableCollection<UIAccountData> _accountlist;
public ObservableCollection<UIAccountData> Accountlist
{
get => _accountlist;
set
{
_accountlist = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
// demo values
Accountlist = new ObservableCollection<UIAccountData>
{
new UIAccountData { Type = UserAccountType.Cash, Number = "123", Status = AccountStatus.Active, IsPrimary = true, IsBilling = true, ClientAccountType = ClientAccountType.Individual },
new UIAccountData { Type = UserAccountType.Margin, Number = "aaa", Status = AccountStatus.Active, IsPrimary = false, IsBilling = true, ClientAccountType = ClientAccountType.InformalTrust },
new UIAccountData { Type = UserAccountType.LRRSP, Number = "bbb", Status = AccountStatus.SuspendedClosed, IsPrimary = true, IsBilling = false, ClientAccountType = ClientAccountType.Partnership },
new UIAccountData { Type = UserAccountType.SRIF, Number = "456", Status = AccountStatus.SuspendedViewOnly, IsPrimary = false, IsBilling = false, ClientAccountType = ClientAccountType.Institution },
};
AccountData account = new AccountData() { m_type = UserAccountType.FX, m_number = "fff", m_status = AccountStatus.SuspendedViewOnly, m_isPrimary = true, m_isBilling = false, m_clientAccountType = ClientAccountType.Institution };
Accountlist.Add(new UIAccountData(account));
}
}
完整标记
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1"
Title="MainWindow" Height="600" Width="1000" WindowStartupLocation="CenterScreen">
<Window.DataContext>
<local:MainViewModel/><!-- MainViewModel attached here -->
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Accountlist}" HorizontalAlignment="Left" AutoGenerateColumns="False" IsReadOnly="True" Width="Auto">
<DataGrid.Columns>
<DataGridTextColumn Width="*" Header="Type" Binding="{Binding Type}"/>
<DataGridTextColumn Width="*" Header="Number" Binding="{Binding Number}"/>
<DataGridTextColumn Width="*" Header="Status" Binding="{Binding Status}"/>
<DataGridCheckBoxColumn Width="*" Header="IsPrimary" Binding="{Binding IsPrimary}"/>
<DataGridCheckBoxColumn Width="*" Header="IsBilling" Binding="{Binding IsBilling}"/>
<DataGridTextColumn Width="*" Header="ClientAccountType" Binding="{Binding ClientAccountType}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
最后
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}