数据网格内的Combobox多次引发选择更改事件

时间:2015-08-20 13:10:44

标签: c# wpf mvvm mvvm-light wpfdatagrid

我有一个带RowDetailsTemplate的WPF数据网格,其中包含一个显示子记录的内部数据网格和一个用于添加新记录的用户控件(其中包含一个组合框和一个按钮)。基于组合框选择更改我必须从数据库加载一些数据,并在按钮单击时我想将该记录保存到子集合中。

查看

<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Width="150"
                                                Binding="{Binding Name}"
                                                Header="NAME" />

                <DataGridTextColumn Width="150"
                                                Binding="{Binding Email}"
                                                Header="EMAIL" />
            </DataGrid.Columns>
            <DataGrid.RowDetailsTemplate>
                <DataTemplate>
                    <StackPanel Margin="10">
                        <ComboBox ItemsSource="{Binding Source={StaticResource Locator},Path=Main.Organizations}" 
                                  SelectedItem="{Binding Source={StaticResource Locator},Path=Main.SelectedOrganization}"                                       
                                  DisplayMemberPath="Name" SelectedValuePath="Id">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="SelectionChanged">
                                    <command:EventToCommand Command="{Binding Source={StaticResource Locator},
                                                                                                  Path=Main.SelectionChangedCommand}"
                                                                                PassEventArgsToCommand="False" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </ComboBox>

                        <Button Command="{Binding Source={StaticResource Locator},Path=Main.ButtonClickCommand}" Content="Click!" Height="50" Width="100"></Button>

                    </StackPanel>
                </DataTemplate>
            </DataGrid.RowDetailsTemplate>
        </DataGrid>

查看模型

/// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            ////if (IsInDesignMode)
            ////{
            ////    // Code runs in Blend --> create design time data.
            ////}
            ////else
            ////{
            ////    // Code runs "for real"
            ////}

            Employees = GetEmployees();

            Organizations = GetOrganizations();
        }

        private ObservableCollection<Organization> GetOrganizations()
        {
            return new ObservableCollection<Organization>()
            {
                new Organization() {Id = 1, Name = "Org Name 1"},
                new Organization() {Id = 2, Name = "Org Name 2"},
                new Organization() {Id = 3, Name = "Org Name 3"},
                new Organization() {Id = 4, Name = "Org Name 4"},
                new Organization() {Id = 5, Name = "Org Name 5"}
            };
        }

        private ObservableCollection<Employee> GetEmployees()
        {
            return new ObservableCollection<Employee>()
            {
                new Employee() {Id = 1, Email = "Email 1", Name = "Name 1"},
                new Employee() {Id = 2, Email = "Email 2", Name = "Name 2"},
                new Employee() {Id = 3, Email = "Email 3", Name = "Name 3"},
                new Employee() {Id = 4, Email = "Email 4", Name = "Name 4"},
                new Employee() {Id = 5, Email = "Email 5", Name = "Name 5"}
            };
        }

        private ObservableCollection<Employee> _employees;
        public ObservableCollection<Employee> Employees
        {
            get { return _employees; }

            set
            {
                _employees = value;
                RaisePropertyChanged(()=>Employees);
            }
        }

        private ObservableCollection<Organization> _organizations;
        public ObservableCollection<Organization> Organizations
        {
            get { return _organizations; }

            set
            {
                _organizations = value;
                RaisePropertyChanged(() => Organizations);
            }
        }

        private Organization _selectedOrganization;
        public Organization SelectedOrganization
        {
            get { return _selectedOrganization; }

            set
            {
                _selectedOrganization = value;
                RaisePropertyChanged(() => SelectedOrganization);
            }
        }

        private RelayCommand _selectionChangedCommand;
        public RelayCommand SelectionChangedCommand
        {
            get
            {
                return _selectionChangedCommand ??
                       (_selectionChangedCommand =
                           new RelayCommand(() => OnSelectionChange()));
            }
        }

        private RelayCommand _buttonClickCommand;
        public RelayCommand ButtonClickCommand
        {
            get
            {
                return _buttonClickCommand ??
                       (_buttonClickCommand =
                           new RelayCommand(() => OnButtonClick()));
            }
        }

        private void OnButtonClick()
        {
            //button click event
        }

        private void OnSelectionChange()
        {
            //combobox selection change event
        }
    }

让我们来看看问题,对于第一个数据网格行选择,一切都按预期正常工作。选择另一行并从组合框中选择一项将激活SelectionChanged事件两次。计数将根据数据网格行选择而增加。我该如何处理这种情况?这是与路由事件有关的吗?我还没有为组合框或数据网格注册任何其他事件。

此问题的一种解决方法是在SelectedOrganization set方法上加载数据。但我必须使数据库调用异步。那么处理像这样的场景的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

在SetClick of ButtonClickCommand属性中,您设置变量_selectionChangedCommand,而不是_buttonClickCommand:

public RelayCommand ButtonClickCommand
{
    get
    {
        return _buttonClickCommand ??
            (_buttonClickCommand =
                new RelayCommand(() => OnButtonClick()));
            }
    set 
    { 
        _buttonClickCommand = value; 
    }
}

另外,我不喜欢在getter中初始化命令的方法。我认为你应该将初始化移动到ViewModel的构造函数。

public MainViewModel()
{
    SelectionChangedCommand=
        new RelayCommand(() => OnSelectionChange()));
}

public RelayCommand SelectionChangedCommand {get;set;}