【问题标题】:WPF DataGrid SelectionChange event doesn't fire when ItemsSourse is being set from UserControl当从 UserControl 设置 ItemsSourse 时,WPF DataGrid SelectionChange 事件不会触发
【发布时间】:2014-08-12 06:44:53
【问题描述】:

我这里有一个非常有趣的场景,看:

主窗口 XAML:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <TabControl Grid.Row="0"
                Grid.Column="0"
                SelectionChanged="Selector_OnSelectionChanged">
        <TabItem Header="First"/>
        <TabItem Header="Second"/>
    </TabControl>
    <ContentPresenter Grid.Column="1"
                      Content="{Binding SelectedUserControl}">

    </ContentPresenter>
</Grid>

UserControlOne XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <DataGrid Grid.Row="0"
              ItemsSource="{Binding DataSource}"
              SelectedItem="{Binding SelectedItem}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <Command:EventToCommand Command="{Binding SelectionChangedCommand}" 
                                        CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DataGrid>
    <Button Grid.Row="1" 
            Content="SetSource"
            Height="50"
            Command="{Binding SetSourceCommand}"/> 
    <Button Grid.Row="2" 
            Content="RemoveSource"
            Height="50"
            Command="{Binding RemoveSourceCommand}"/>
</Grid>

UserContolTwo XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition></RowDefinition>
        <RowDefinition></RowDefinition>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" 
                        Content="SetSource"
                        Height="50"
                        Command="{Binding SetSourceCommand}"/>
    <Button Grid.Row="1" 
                        Content="RemoveSource"
                        Command="{Binding RemoveSourceCommand}"
                        Height="50"/>
</Grid>

代码隐藏:

public class GridItem
{
    public String Name { get; set; }
    public override string ToString()
    {
        return Name;
    }
}


public partial class Window1 : Window, INotifyPropertyChanged
{
    private List<GridItem> _items;
    private GridItem _selectedItem;
    private List<GridItem> _dataSource;
    private readonly List<UserControl> _userControlList;
    private UserControl _selectedUserControl;


    public UserControl SelectedUserControl
    {
        get { return _selectedUserControl; }
        set
        {
            _selectedUserControl = value;
            RaisePropertyChanged("SelectedUserControl");
        }
    }


    public GridItem SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            RaisePropertyChanged("SelectedItem");
        }
    }

    public List<GridItem> DataSource
    {
        get { return _dataSource; }
        set
        {
            _dataSource = value;
            RaisePropertyChanged("DataSource");
        }
    }

    public Window1()
    {
        InitializeComponent();
        DataContext = this;

        _items = new List<GridItem>
        {
            new GridItem { Name = "Igor" },
            new GridItem { Name = "Vasya"},
            new GridItem { Name = "Vladlen"}
        };

        _userControlList = new List<UserControl>
        {
            new UserControl1(),
            new UserControl2()
        };
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged

    private void Selector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        SelectedUserControl = _userControlList[((TabControl)sender).SelectedIndex];
    }


    #region SetSourceCommand

    private RelayCommand<Object> _setSourceCommand;
    public RelayCommand<Object> SetSourceCommand
    {
        get
        {
            return _setSourceCommand ?? (_setSourceCommand =
                new RelayCommand<Object>(SetSourceMethod));
        }
    }

    private void SetSourceMethod(Object obj)
    {
        DataSource = _items;
        SelectedItem = _items.FirstOrDefault();
    }

    #endregion SetSourceCommand


    #region RemoveSourceCommand

    private RelayCommand<Object> _removeSourceCommand;
    public RelayCommand<Object> RemoveSourceCommand
    {
        get
        {
            return _removeSourceCommand ?? (_removeSourceCommand =
                new RelayCommand<Object>(RemoveSourceMethod));
        }
    }

    private void RemoveSourceMethod(Object obj)
    {
        DataSource = null;
    }

    #endregion RemoveSourceCommand   


    #region SelectionChangedCommand

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

    private void SelectionChangedMethod(Object obj)
    {
        Debug.WriteLine("Event have been rised! Selected item is {0}", ((DataGrid)obj).SelectedItem ?? "NULL");    
    }

    #endregion RemoveSourceCommand
}

我有MainWindow,其中包含UserControlUserControl 被动态设置,所以如果你选择FirstTabItem,那么UserControlOne 将被加载,如果你选择SecondTabItem - UserControlTwo 将被加载到ContentPresenterMainWindow 中。

如果我在FirstTabItem 上单击按钮SetSource(实际上是在UserControlOne 上) - 那么DataGridSelectionChanged 事件会像往常一样触发。但是,如果我单击 SecondTabItem 上的按钮 SetSource(实际上是在 UserControlTwo 上) - 那么 SelectionChangedDataGrid 事件根本不会触发。尽管两个按钮都绑定到同一个命令 (SetSourceCommand)。

如果按钮未放置在其他控件上,例如,仅放置在同一 TabControl 的不同标签项上 - 按钮会调用 SelectionChange 事件。所以真正的问题在于标记,使用UserControls

有人遇到过这个问题吗?我该如何解决?我不想以编程方式调用事件处理程序。

我在这里发布了所有必需的代码,所以你可以复制粘贴它并很快自己尝试。或者,如果有人感兴趣,我可以加载示例项目。

【问题讨论】:

  • 您能以压缩格式发布解决方案吗?
  • @aks81,这里是link
  • 将尝试返回解决方案。谢谢。
  • @aks81 没有结果或者你还没试过?
  • 对不起昨天我没有时间尝试:(

标签: wpf datagrid user-controls selectionchanged


【解决方案1】:

好的,这是您代码中的实际问题。

UserControl1 有一个网格,您在其中使用了SelectedItem 依赖属性。在这个特定的 DP 上,您有一个 Command SelectionChangedCommand

在您的命令SetSourceCommandRemoveSourceCommand 中,您正在更新由于事件SelectionChanged 而触发SelectionChangedCommand 的数据网格的SelectedItem

在您的UserControl2 中没有数据网格,也没有任何控件可以触发SelectionChanged 事件来调用SelectionChangedCommand。因此它永远不会被执行。

【讨论】:

  • 很明显,当当前加载的UserControl 没有DataGrid 并且问题是How can I fix it? 时,事件不会触发。似乎问题没有解决方案,是吗?顺便说一句,现在我看到我完全错误地理解了DataGridSelectionChange 事件。它在Selection 更改而不是SelectedItem 更改时触发。我想我可以通过SelectedItemChanged 事件创建自己的DataGrid
  • SelectedItem 在内部触发SelectionChanged 事件。无论是通过用户交互还是以编程方式,SelectedItem 属性发生变化时,都会触发 SelectionChanged 事件。
  • 只是一个模糊的想法。在您的UserControl2 中,为什么不使用VisibilityCollapsed 定义一个DataGrid,这在UI 上不可见,但有助于触发SelectionChangedCommand
  • 但正如我们所见,如果 SelectedItem 属性更改,如果 DataGrid 实际上没有显示,SelectionChanged 不会触发。
  • 那是因为在您的UserControl2 中没有控制需要处理SelectionChangedCommand
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多