代码之家  ›  专栏  ›  技术社区  ›  Mark Cooper

Silverlight关联两个数据网格

  •  1
  • Mark Cooper  · 技术社区  · 15 年前

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

    详细内容: 我的视图中有两个数据网格。第一个显示团队的集合,第二个显示所选团队中的人员列表。

    选定团队 属性已正确更新,但人员网格未填充。

    注意:我不能使用嵌套网格,也不能使用SL数据网格中提供的酷主细节功能。

    更新: 为什么ComboBox.SelectedItem和DataGrid.SelectedItem的行为会如此不同?


    做记号


    视图:

    <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>
    

    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");
                }
            }
    
        }
    }
    

    用组合框替换第一个数据网格,一切正常。为什么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 回复  |  直到 15 年前
        1
  •  1
  •   AnthonyWJones    15 年前

    已经做了一些测试。

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

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

    因此,问题被缩小到一个数据网格上的SelectedItem,通过框架绑定引擎连接到另一个数据网格的ItemsSource。

    Data 命名空间包含一个扩展静态类目标 DependencyObject 它有一个 AreHandlersSuspended

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

    有人得到了SL4,并对其进行了奇特的测试吗?

    如果SL4仍有漏洞,则需要报告以作为漏洞连接。

        2
  •  1
  •   Mark Cooper    15 年前

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

    这是受来自 John Papa ,我已经写了一篇关于这方面的详细文章 http://thoughtjelly.blogspot.com/2009/12/binding-selecteditem-to-itemssource.html .

    [心满意足地坐在后面点燃一支雪茄]
    做记号

        3
  •  1
  •   David Bridges    15 年前

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

    代码隐藏:

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

    型号:

        public void RefreshDetail()
        {
            RaisePropertyChanged("Detail");
        }
    
        4
  •  0
  •   Tim Cooper    13 年前

    我有工作要做。它有一点代码落后,因此不会受到纯粹的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 .

    希望这对其他人有帮助。

    推荐文章