通过 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);
            }
        }
    }
}

AccountServiceMarketService 都在使用 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 包含项目。如果可能的话,我想让 ViewViewModel 响应 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 中,它们没有引用内存中的相同引用,也没有以任何方式同步。