【问题标题】:Bind DataGrid to Model Collection via ViewModel通过 ViewModel 将 DataGrid 绑定到模型集合
【发布时间】:2016-05-03 04:35:49
【问题描述】:

我是 Caliburn.Micro 的新手,但已经完成了一些基本的 WPF MVVM 编程,因此了解这些概念。我倾向于以模型优先的风格进行开发,因此在将 WPF DataGrid 绑定到在 Model 中定义和更新的集合时遇到问题。我应该如何最好地通过ViewModelView 公开对Collection 的引用,以便Model 中的任何更新都通过ViewModel 引用传播,而不必在@ 中连接987654328@?

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 都在 AppBootsrapper 中注册为单例,使用 Simple Injector 作为 DI 框架。

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 响应Model BindableCollection 的更改/更新?

谢谢。

【问题讨论】:

    标签: c# wpf mvvm datagrid caliburn.micro


    【解决方案1】:

    为什么要使用 Markets 的单独集合?常见的设计是使用

    public BindableCollection<Market> Markets
    {
        get { return _MarketService.Markets; }
        set
        {
            if (_MarketService.Markets != value)
            {
                _MarketService.Markets = value;
                NotifyOfPropertyChange(() => Markets);
            }
        }
    }
    

    现在您有两个单独的集合,一个在 ShellViewModel.Markets 中,一个在 ShellViewModel.MarketService.Markets 中,它们没有引用内存中的相同引用或以任何方式同步。

    【讨论】:

    • 谢谢瑞秋。我确定我早些时候尝试过,它给了我一个线程异常,但现在可以工作了!
    【解决方案2】:

    您需要将您的datagrid 绑定到您的BindableCollection

    在你的 xaml 中试试这个ItemsSource={Binding Markets}

    【讨论】:

    • 感谢您的回复。我的印象是,对于 Caliburn.Micro,使用约定 'x:Name="Markets"' 会处理绑定?
    • @percentum 是的,我认为这就是 Caliburn Micro 的工作方式。它使用Name 属性创建通用绑定,因此如果DataGrid 名为Markets,它将创建DataGrid.ItemsSource{Binding Markets} 的绑定
    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-11
    • 2012-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多