通过 ViewModel 将 DataGrid 绑定到模型集合
Bind DataGrid to Model Collection via ViewModel
我是 Caliburn.Micro 的新手,但已经完成了一些基本的 WPF MVVM 编程,因此了解这些概念。我倾向于以模型优先的方式进行开发,因此在将 WPF DataGrid
绑定到 Model
中定义和更新的集合时遇到问题。我应该如何最好地通过 ViewModel
将对 Collection
的引用暴露给 View
,以便 Model
中的任何更新都通过 ViewModel
引用传播,而不必在 ViewModel
?
中连接
Model
:
public class Market : PropertyChangedBase
{
private string _MarketGroup;
public string MarketGroup
{
get
{
return _MarketGroup;
}
set
{
if (_MarketGroup != value)
{
_MarketGroup = value;
NotifyOfPropertyChange(() => MarketGroup);
}
}
}
private string _Expiry;
public string Expiry
{
get
{
return _Expiry;
}
set
{
if (_Expiry != value)
{
_Expiry = value;
NotifyOfPropertyChange(() => Expiry);
}
}
}
private string _MarketStatus;
public string MarketStatus
{
get
{
return _MarketStatus;
}
set
{
if (_MarketStatus != value)
{
_MarketStatus = value;
NotifyOfPropertyChange(() => MarketStatus);
}
}
}
private string _Epic;
public string Epic
{
get
{
return _Epic;
}
set
{
if (_Epic != value)
{
_Epic = value;
NotifyOfPropertyChange(() => Epic);
}
}
}
private string _InstrumentName;
public string InstrumentName
{
get
{
return _InstrumentName;
}
set
{
if (_InstrumentName != value)
{
_InstrumentName = value;
NotifyOfPropertyChange(() => InstrumentName);
}
}
}
}
public interface IMarketService : InotifyPropertyChanged
{
BindableCollection<Market> Markets {get;}
void RefreshMarkets();
}
public class MarketService : PropertyChangedBase, IMarketService
{
public MarketService()
{
Markets = new BindableCollection<IGMarket>();
}
private BindableCollection<Market> _Markets;
public BindableCollection<Market> Markets
{
get
{
return _Markets;
}
private set
{
if (_Markets!= value)
{
_Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
public void RefreshMarkets()
{
Markets.Clear();
var markets = GetMarkets();
foreach (var market in markets)
{
Markets.Add(market);
}
}
}
ViewModel
:
public class ShellViewModel : PropertyChangedBase
{
private readonly IMarketService _MarketService;
private readonly IAccountService _AccountService;
public ShellViewModel(IMarketService marketService, IAccountService accountService)
{
_MarketService = marketService;
_AccountService = accountService;
Markets = new BindableCollection<IGMarket>(_MarketService.Markets);
}
public void Login()
{
Task.Run(() =>
{
if (_AccountService.Login())
{
LoggedIn = true;
_MarketService.RefreshMarkets();
}
});
}
private BindableCollection<Market> _Markets;
public BindableCollection<Market> Markets
{
get { return _Markets; }
set
{
if (_Markets != value)
{
_Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
}
AccountService
和 MarketService
都在使用 Simple Injector 作为 DI 框架的 AppBootsrapper
中注册为单例。
View
:
<DataGrid AutoGenerateColumns="False" ColumnWidth="*" HorizontalAlignment="Stretch" x:Name="Markets" Margin="0,0,0,0" CanUserAddRows="False" CanUserDeleteRows="False" VerticalAlignment="Stretch" Height="auto" Width="auto" Grid.ColumnSpan="2">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding InstrumentName}" Header="Instrument Name" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding Expiry}" Header="Expiry" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding MarketGroup}" Header="Market Group" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding InstrumentType}" Header="Instrument Type" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding MarketStatus}" Header="Market Status" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
Grid
上基本没有任何内容,尽管 _MarketService.Markets
包含项目。如果可能的话,我想让 View
和 ViewModel
响应 changes/updates 到 Model
BindableCollection
?
谢谢。
您需要将 datagrid
绑定到 BindableCollection
在您的 xaml ItemsSource={Binding Markets}
中试试这个
为什么要使用 Markets
的单独集合?常见的设计是使用
public BindableCollection<Market> Markets
{
get { return _MarketService.Markets; }
set
{
if (_MarketService.Markets != value)
{
_MarketService.Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
现在您有两个单独的集合,一个在 ShellViewModel.Markets
中,一个在 ShellViewModel.MarketService.Markets
中,它们没有引用内存中的相同引用,也没有以任何方式同步。
我是 Caliburn.Micro 的新手,但已经完成了一些基本的 WPF MVVM 编程,因此了解这些概念。我倾向于以模型优先的方式进行开发,因此在将 WPF DataGrid
绑定到 Model
中定义和更新的集合时遇到问题。我应该如何最好地通过 ViewModel
将对 Collection
的引用暴露给 View
,以便 Model
中的任何更新都通过 ViewModel
引用传播,而不必在 ViewModel
?
Model
:
public class Market : PropertyChangedBase
{
private string _MarketGroup;
public string MarketGroup
{
get
{
return _MarketGroup;
}
set
{
if (_MarketGroup != value)
{
_MarketGroup = value;
NotifyOfPropertyChange(() => MarketGroup);
}
}
}
private string _Expiry;
public string Expiry
{
get
{
return _Expiry;
}
set
{
if (_Expiry != value)
{
_Expiry = value;
NotifyOfPropertyChange(() => Expiry);
}
}
}
private string _MarketStatus;
public string MarketStatus
{
get
{
return _MarketStatus;
}
set
{
if (_MarketStatus != value)
{
_MarketStatus = value;
NotifyOfPropertyChange(() => MarketStatus);
}
}
}
private string _Epic;
public string Epic
{
get
{
return _Epic;
}
set
{
if (_Epic != value)
{
_Epic = value;
NotifyOfPropertyChange(() => Epic);
}
}
}
private string _InstrumentName;
public string InstrumentName
{
get
{
return _InstrumentName;
}
set
{
if (_InstrumentName != value)
{
_InstrumentName = value;
NotifyOfPropertyChange(() => InstrumentName);
}
}
}
}
public interface IMarketService : InotifyPropertyChanged
{
BindableCollection<Market> Markets {get;}
void RefreshMarkets();
}
public class MarketService : PropertyChangedBase, IMarketService
{
public MarketService()
{
Markets = new BindableCollection<IGMarket>();
}
private BindableCollection<Market> _Markets;
public BindableCollection<Market> Markets
{
get
{
return _Markets;
}
private set
{
if (_Markets!= value)
{
_Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
public void RefreshMarkets()
{
Markets.Clear();
var markets = GetMarkets();
foreach (var market in markets)
{
Markets.Add(market);
}
}
}
ViewModel
:
public class ShellViewModel : PropertyChangedBase
{
private readonly IMarketService _MarketService;
private readonly IAccountService _AccountService;
public ShellViewModel(IMarketService marketService, IAccountService accountService)
{
_MarketService = marketService;
_AccountService = accountService;
Markets = new BindableCollection<IGMarket>(_MarketService.Markets);
}
public void Login()
{
Task.Run(() =>
{
if (_AccountService.Login())
{
LoggedIn = true;
_MarketService.RefreshMarkets();
}
});
}
private BindableCollection<Market> _Markets;
public BindableCollection<Market> Markets
{
get { return _Markets; }
set
{
if (_Markets != value)
{
_Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
}
AccountService
和 MarketService
都在使用 Simple Injector 作为 DI 框架的 AppBootsrapper
中注册为单例。
View
:
<DataGrid AutoGenerateColumns="False" ColumnWidth="*" HorizontalAlignment="Stretch" x:Name="Markets" Margin="0,0,0,0" CanUserAddRows="False" CanUserDeleteRows="False" VerticalAlignment="Stretch" Height="auto" Width="auto" Grid.ColumnSpan="2">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding InstrumentName}" Header="Instrument Name" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding Expiry}" Header="Expiry" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding MarketGroup}" Header="Market Group" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding InstrumentType}" Header="Instrument Type" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding MarketStatus}" Header="Market Status" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
Grid
上基本没有任何内容,尽管 _MarketService.Markets
包含项目。如果可能的话,我想让 View
和 ViewModel
响应 changes/updates 到 Model
BindableCollection
?
谢谢。
您需要将 datagrid
绑定到 BindableCollection
在您的 xaml ItemsSource={Binding Markets}
为什么要使用 Markets
的单独集合?常见的设计是使用
public BindableCollection<Market> Markets
{
get { return _MarketService.Markets; }
set
{
if (_MarketService.Markets != value)
{
_MarketService.Markets = value;
NotifyOfPropertyChange(() => Markets);
}
}
}
现在您有两个单独的集合,一个在 ShellViewModel.Markets
中,一个在 ShellViewModel.MarketService.Markets
中,它们没有引用内存中的相同引用,也没有以任何方式同步。