关于两个Datagrids的Silverlight

时间:2009-12-01 14:39:48

标签: silverlight silverlight-3.0 datagrid

我的问题:如何将SelectedItem从主数据网格绑定到辅助数据网格的ItemsSource?

详细说明: 我的观点中有两个数据网格。第一个显示团队的集合,第二个显示为所选团队中的人员列表。

当我从网格中选择一个团队时,我可以看到 SelectedTeam 属性正在正确更新,但人员网格没有被填充。

注意:我无法使用嵌套网格或SL数据网格中提供的很酷的主要细节功能。

UPDATE:使用ComboBox替换父数据网格会产生完全不同的结果,并且运行正常。 为什么ComboBox.SelectedItem和DataGrid.SelectedItem的行为如此不同?

谢谢,
标记


Simple Repro:

查看:

<UserControl x:Class="NestedDataGrid.MainPage"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data">
    <StackPanel x:Name="LayoutRoot">
        <TextBlock Text="Teams:" />
        <data:DataGrid ItemsSource="{Binding Teams}"
                       SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
                       AutoGenerateColumns="False">
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Header="Id" Binding="{Binding TeamId}" />
                <data:DataGridTextColumn Header="Desc" Binding="{Binding TeamDesc}" />
            </data:DataGrid.Columns>
        </data:DataGrid>
        <TextBlock Text="Peeps:" />
        <data:DataGrid ItemsSource="{Binding SelectedTeam.People}"
                       AutoGenerateColumns="False">
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Header="Id"
                                         Binding="{Binding PersonId}" />
                <data:DataGridTextColumn Header="Name"
                                         Binding="{Binding Name}" />
            </data:DataGrid.Columns>
        </data:DataGrid>
    </StackPanel>
</UserControl>

CODE_BEHIND:

using System.Windows.Controls;
namespace NestedDataGrid
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            this.LayoutRoot.DataContext = new ViewModel();
        }

    }
}

视图模型:

using System.Collections.ObjectModel;
namespace NestedDataGrid
{
    public class ViewModel: ObjectBase
    {
        public ViewModel()
        {
            ObservableCollection<Person> RainbowPeeps = new ObservableCollection<Person>()
            {
                new Person(){ PersonId=1, Name="George"}, 
                new Person(){ PersonId=2, Name="Zippy"}, 
                new Person(){ PersonId=3, Name="Bungle"}, 
            };

            ObservableCollection<Person> Simpsons = new ObservableCollection<Person>()
            {
                new Person(){ PersonId=4, Name="Moe"}, 
                new Person(){ PersonId=5, Name="Barney"}, 
                new Person(){ PersonId=6, Name="Selma"}, 
            };

            ObservableCollection<Person> FamilyGuyKids = new ObservableCollection<Person>()
            {
                new Person(){ PersonId=7, Name="Stewie"}, 
                new Person(){ PersonId=8, Name="Meg"}, 
                new Person(){ PersonId=9, Name="Chris"}, 
            };


            Teams = new ObservableCollection<Team>()
            {
                new Team(){ TeamId=1, TeamDesc="Rainbow", People=RainbowPeeps},
                new Team(){ TeamId=2, TeamDesc="Simpsons", People=Simpsons},
                new Team(){ TeamId=3, TeamDesc="Family Guys", People=FamilyGuyKids },
            };
        }


        private ObservableCollection<Team> _teams;
        public ObservableCollection<Team> Teams
        {
            get { return _teams; }
            set
            {
                SetValue(ref _teams, value, "Teams");
            }
        }


        private Team _selectedTeam;
        public Team SelectedTeam
        {
            get { return _selectedTeam; }
            set
            {
                SetValue(ref _selectedTeam, value, "SelectedTeam");
            }
        }


    }
}

相关课程:

using System;
using System.ComponentModel;

namespace NestedDataGrid
{
    public abstract class ObjectBase : Object, INotifyPropertyChanged
    {
        public ObjectBase()
        { }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void _OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler pceh = PropertyChanged;
            if (pceh != null)
            {
                pceh(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        protected virtual bool SetValue<T>(ref T target, T value, string propertyName)
        {
            if (Object.Equals(target, value))
            {
                return false;
            }

            target = value;
            _OnPropertyChanged(propertyName);

            return true;
        }

    }


    public class Person: ObjectBase
    {
        private int  _personId;
        public int PersonId
        {
            get { return _personId; }
            set
            {
                SetValue(ref _personId, value, "PersonId");
            }
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                SetValue(ref _name, value, "Name");
            }
        }

    }

    public class Team : ObjectBase
    {

        private int _teamId;
        public int TeamId
        {
            get { return _teamId; }
            set
            {
                SetValue(ref _teamId, value, "TeamId");
            }
        }

        private string _teamDesc;
        public string TeamDesc
        {
            get { return _teamDesc; }
            set
            {
                SetValue(ref _teamDesc, value, "TeamDesc");
            }
        }


        private ObservableCollection<Person> _people;
        public ObservableCollection<Person> People
        {
            get { return _people; }
            set
            {
                SetValue(ref _people, value, "People");
            }
        }

    }
}

更新

用组合框和eveything替换第一个数据网格可以正常工作。为什么DataGrid.SelectedItem和ComboBox.SelectedItem的行为如此不同?

<StackPanel x:Name="LayoutRoot">        
    <TextBlock Text="Teams:" />
    <ComboBox SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
                    ItemsSource="{Binding Teams}"/>
    <TextBlock Text="{Binding SelectedTeam}" />    
    <TextBlock Text="Peeps:" />
    <data:DataGrid ItemsSource="{Binding SelectedTeam.People}" />    
</StackPanel>

4 个答案:

答案 0 :(得分:1)

做了一些测试。

首先,我只想确认Binding本身是否正常工作。当为ListBox换出第二个DataGrid时,它非常有用。到目前为止,我已经确认第二个DataGrid的绑定引擎改变了其ItemsSource属性。

我还为ListBox换出了第一个DataGrid,然后第二个DataGrid开始工作得很开心。

此外,如果您在第一个数据网格上连接SelectionChanged事件并使用代码直接分配给第二个数据网格,它就会开始工作。

我还删除了第一个Grid上的SelectedItem绑定,并从第二个Grid的ItemsSource属性上设置了一个ElementToElement绑定。仍然没有快乐。

因此,问题通过框架绑定引擎缩小到一个DatGrid上的SelectedItem和另一个的ItemsSource。

Reflector提供了一条可能的线索。 Data命名空间包含一个Extensions静态类,其目标是DependencyObject,其AreHandlersSuspended方法由静态变量支持。代码处理更改为ItemsSource属性的方法使用此方法,如果返回true则不执行任何操作。

我未经证实的怀疑是,在第一个Grid分配其SelectedItem属性的过程中,它已打开标志以避免无限循环。但是,由于此标志实际上是全局的,因此不会执行因此SelectedItem赋值而运行的任何其他合法代码。

任何人都有SL4和花式测试吗? 任何潜伏的MSFT人都想看看?

如果SL4仍然拥有它,则需要向Connect报告错误。

答案 1 :(得分:1)

更好的解决方案是使用add DataGridRowSelected命令。这比我之前的鼠标点击示例更适合MVVM模式。

这受到John Papa的一些代码的启发,我已经创建了一篇关于此http://thoughtjelly.blogspot.com/2009/12/binding-selecteditem-to-itemssource.html的详细信息。

[坐下来满足并点燃一支雪茄]
标记

答案 2 :(得分:1)

我遇到了同样的问题,并通过将其添加到我的代码隐藏中来“修复”它。

代码背后:

    private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (_model != null)
        {
            _model.RefreshDetail();
        }
    }

型号:

    public void RefreshDetail()
    {
        RaisePropertyChanged("Detail");
    }

答案 3 :(得分:0)

我有一个解决方法。它涉及一些代码背后,所以不会受到纯粹的MVVM狂热者的青睐! ; - )

<StackPanel x:Name="LayoutRoot">        
    <TextBlock Text="Teams:" />
    <data:DataGrid x:Name="dgTeams"
                   SelectedItem="{Binding SelectedTeam, Mode=TwoWay}"
                   ItemsSource="{Binding Teams}" />
    <TextBlock Text="{Binding SelectedTeam}" />
    <TextBlock Text="Peeps:" />
    <data:DataGrid x:Name="dgPeeps" />
</StackPanel>

代码背后:

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();
        this.LayoutRoot.DataContext = new ViewModel();

        dgTeams.MouseLeftButtonUp += new MouseButtonEventHandler(dgTeams_MouseLeftButtonUp)
    }

    void dgTeams_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        DataGridRow row = DependencyObjectHelper.FindParentOfType<DataGridRow>(e.OriginalSource as DependencyObject);

        ///get the data object of the row
        if (row != null && row.DataContext is Team)
        {
            dgPeeps.ItemsSource = (row.DataContext as Team).People;
        }
    }

}

FindParentOfType 方法详见:http://thoughtjelly.blogspot.com/2009/09/walking-xaml-visualtree-to-find-parent.html

希望这有助于其他人。