【问题标题】:Silverlight: how to bind List<T> to data gridSilverlight:如何将 List<T> 绑定到数据网格
【发布时间】:2011-03-29 21:11:59
【问题描述】:

MVVM 模式在我的 Silverlight4 应用程序中实现。

最初,我在 ViewModel 中使用 ObservableCollection 对象:

public class SquadViewModel : ViewModelBase<ISquadModel>
{
    public SquadViewModel(...) : base(...)
    {
        SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
        ...
        _model.DataReceivedEvent += _model_DataReceivedEvent;
        _model.RequestData(...);
    }

    private void _model_DataReceivedEvent(ObservableCollection<TeamPlayerData> allReadyPlayers, ...)
    {
        foreach (TeamPlayerData tpd in allReadyPlayers)
        {
            SquadPlayerViewModel sp = new SquadPlayerViewModel(...);
            SquadPlayers.Add(sp);
        }
    }
    ...
}

这是用于网格显示的 XAML 代码:

xmlns:DataControls="clr-namespace:System.Windows.Controls;
                    assembly=System.Windows.Controls.Data"
...
<DataControls:DataGrid ItemsSource="{Binding SquadPlayers}">
    ...</DataControls:DataGrid>

我的 ViewModel 绑定到视图的 DataContext 属性。

此集合(SquadPlayers)在创建后没有更改,因此我想将其类型更改为

List<SquadPlayerViewModel>

。当我这样做时,我还添加了

RaisePropertyChanged("SquadPlayers")

在 '_model_DataReceivedEvent' 方法的末尾(通知网格列表数据已更改。

问题是,在初始显示网格不显示任何记录...只有当我点击任何列标题时,它才会“排序”并显示列表中的所有项目...

问题1:为什么datagrid最初不包含项目? Q2:如何让它们自动显示?

谢谢。

附:这是我的视图模型中新 List 对象的声明:

        public List<SquadPlayerViewModel> SquadPlayers { get; set; }

【问题讨论】:

    标签: silverlight mvvm datagrid silverlight-4.0 observablecollection


    【解决方案1】:

    您不能使用 List 作为绑定源,因为 List 没有实现 INotifyCollectionChanged,因此 WPF/Silverlight 需要知道集合的内容是否更改。 WPF/Sivlerlight 可以采取进一步的行动。

    我不知道为什么你的视图模型上需要 List,但如果出于抽象原因,你可以使用 IList 代替。但请确保将 ObservableCollection 的实例放在上面,而不是 List。无论你在你的 ViewModel 中使用什么 Type Binding 只关心运行时类型。

    所以你的代码应该是这样的:

    //Your declaration
    public IList<SquadPlayerViewModel> SquadPlayers { get; set; }
    //in your implementation for WPF/Silverlight you should do
    SquadPlayers = new ObservableCollection<SquadPlayerViewModel>();
    //but for other reason (for non WPF binding) you can do
    SquadPlayers = new List<SquadPlayerViewModel>();
    

    我通常使用这种方法来抽象 NHibernate 返回的“代理”域模型。

    【讨论】:

    • 如果我理解正确,如果我想使用 List 进行绑定,解决方法 (RaisePropertyChanged("SquadPlayers");) 将无济于事。正确的?谢谢。
    • 是和否,如果您分配给SquadPlayers = blah.. blah.. 是,但对于SquadPlayers.Add(blah..blah) 则不是。当集合SquadPlayers 的实例更改为新实例时,标记RaisePropertyChanged("SquadPlayers") 起作用,但这还不够,因为集合需要通知天气其项目已更改(添加或删除)。
    • 有区别,...我看到的第一个问题:我通知集合发生了变化,但实际上集合是一样的,只是它的项目发生了变化。今天我将尝试替换集合(但我想,这将完全破坏绑定)。所以我需要通知集合项目已更改......如果我正确理解 - 这对于 List 是不可能的。我说的对吗?
    【解决方案2】:

    您需要像这样定义您的 SquadPlayers List:


    private ObservableCollection<SquadPlayerViewModel> _SquadPlayers;
        public ObservableCollection<SquadPlayerViewModel> SquadPlayers
        {
            get
            {
                return _SquadPlayers;
            }
    
            set
            {
                if (_SquadPlayers== value)
                {
                    return;
                }
    
                _SquadPlayers= value;
    
                // Update bindings, no broadcast
                RaisePropertyChanged("SquadPlayers");
            }
        }
    

    【讨论】:

    • 嘿,迈克,在我最初的声明中,我提到了可观察的集合在最初的初始化之后不会改变。因此,我打算用 List 替换 ObservableCollection。我没提过吗?
    • 这就是我说“类似”的原因。将 ObservableCollection 替换为 List。这是我拥有的一些工作代码的 sn-p,我只是更改了一些名称以适合您的示例。重点主要是确保 List 被完全定义为一个属性。这是在黑暗中拍摄的,因为我不知道您是如何声明列表或全面了解您的 XAML 的。
    • 迈克,感谢您的宝贵时间。 List 被声明为属性,我已将其添加到描述中。如果您有任何其他想法,请告诉我
    【解决方案3】:

    问题在于,虽然PropertyChanged 事件通知绑定“更改”,但该值实际上并未更改,但集合对象仍然是同一个对象。如果某些控件认为值并没有真正改变,它们会为自己节省一些不必要的工作。

    尝试创建ObservableCollection 的新实例并分配给该属性。在这种情况下,当前分配的对象将不同于您在数据可用时创建的新对象。

    【讨论】:

    • 向网格添加新列表是个好主意,同意...但我不知道如何将新列表从 ViewModel 绑定到网格(即来自视图层的对象)。如果您能澄清这一点,我将不胜感激。谢谢。
    猜你喜欢
    • 2016-06-05
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2018-09-16
    • 2013-10-24
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多