Определите, было ли событие Selector.SelectionChanged инициировано пользователем - PullRequest
38 голосов
/ 14 сентября 2011

Можно ли определить, было ли событие Selector.SelectionChanged инициировано пользователем или программно?

т.е. Мне нужно что-то вроде логического свойства "IsUserInitiated", которое имеет значение true, только если событие SelectionChanged было вызвано, потому что пользователь изменил выбор с помощью мыши или клавиатуры.

Ответы [ 8 ]

23 голосов
/ 29 октября 2013

Простое решение:

Вы можете создать метод, который временно отключит событие SelectionChanged и вызвать его, когда вам нужно изменить выбор программно.

private void SelectGridRow( int SelectedIndex )
{
    myDataGrid.SelectionChanged -= myDataGrid_SelectionChanged;
    myDataGrid.SelectedIndex = SelectedIndex;

    // other work ...

    myDataGrid.SelectionChanged += myDataGrid_SelectionChanged;
}
15 голосов
/ 10 октября 2012

Это должно работать в большинстве сценариев:

private void cboStatus_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (this.cboStatus.IsDropDownOpen)
    {
        //OPTIONAL:
        //Causes the combobox selection changed to not be fired again if anything
        //in the function below changes the selection (as in my weird case)
        this.cboStatus.IsDropDownOpen = false;

        //now put the code you want to fire when a user selects an option here
    }
}
11 голосов
/ 02 февраля 2016

Это проблема, с которой мне приходилось работать с WinForms. Я надеялся, что в WPF они добавят логическое значение к SelectionChangedEventArgs, называемое чем-то вроде IsUserInitiated, как упомянуто в вопросе. Чаще всего это мне нужно, когда я хочу игнорировать все, что происходит во время загрузки данных и привязки к экрану. Например, допустим, что по умолчанию используется поле на основе нового значения в SelectionChanged, НО я хочу, чтобы пользователь мог перезаписывать это значение по умолчанию, и я хочу, чтобы только пользователь перезаписывал его, а НЕ приложение, когда экран перезагружался. Я все еще чувствую, что то, что я делаю, является хакерским, но я опубликую это, потому что я не вижу упоминания. Никаких хитростей, просто и эффективно.

1) Создайте логическое значение уровня класса с именем _loading

private bool _loading;

2) Обновите логическое значение в методе, выполняющем загрузку

private async Task Load()
{
    _loading = true;
    //load some stuff
    _loading = false;
}

3) Используйте логическое значение, когда вам нужно

    private void SetDefaultValue(object sender, SelectionChangedEventArgs e)
    {
        if (!_loading) {
            //set a default value
        }
    }
5 голосов
/ 21 июня 2012

Взято из http://social.msdn.microsoft.com, где пользователь отправляет тот же вопрос

Не думаю, что мы можем различить, было ли событие SelectionChanged инициировано пользовательским вводом или программно. Событию SelectionChanged это не важно.

Как правило, теперь вы всегда можете определить, инициируется ли это программно, потому что это ваш код, который инициирует его.

Если вы используете DataBinding для привязки SelectedItem, вы можете установить для свойств NotifyOnSourceUpdated и NotifyOnTargetUpdated значение True. И вы можете обрабатывать события Binding.SourceUpdated и Binding.TargetUpdated. В большинстве случаев изменение, инициируемое пользовательским вводом, переходит от цели к источнику. Если изменение инициируется программно, оно переходит от источника к цели.

Я не знаю, может ли это помочь ...

3 голосов
/ 22 июня 2012

Вы можете использовать пользовательское перенаправленное событие и подключить соответствующие обработчики в таком поведении:

    public class UserSelectionChangedEventArgs : RoutedEventArgs
    {
        public UserSelectionChangedEventArgs( RoutedEvent id, SelectionChangedEventArgs args , bool changedByUser) :base(id)
        {
            SelectionChangedByUser = changedByUser;
            RemovedItems = args.RemovedItems;
            AddedItems = args.AddedItems;
        }

        public bool SelectionChangedByUser { get; set; }
        public IList RemovedItems { get; set; }
        public IList AddedItems { get; set; }
    }
    public delegate void UserSelectionChangedEventHandler( object sender, UserSelectionChangedEventArgs e );

    public class UserSelectionChangedBehavior : Behavior<Selector>
    {
        private bool m_expectingSelectionChanged;

        public static readonly RoutedEvent UserSelectionChangedEvent = EventManager.RegisterRoutedEvent( "UserSelectionChanged", RoutingStrategy.Bubble, typeof( UserSelectionChangedEventHandler ), typeof( Selector ) );

        public static void AddUserSelectionChangedHandler( DependencyObject d, UserSelectionChangedEventHandler handler )
        {
            ( (Selector) d ).AddHandler( UserSelectionChangedEvent, handler );
        }

        public static void RemoveUserSelectionChangedHandler( DependencyObject d, UserSelectionChangedEventHandler handler )
        {
            ( (Selector) d ).RemoveHandler( UserSelectionChangedEvent, handler );
        }

        private void RaiseUserSelectionChangedEvent( UserSelectionChangedEventArgs args )
        {
            AssociatedObject.RaiseEvent( args );
        }

        protected override void OnAttached()
        {
            AssociatedObject.PreviewKeyDown += OnKeyDown;
            AssociatedObject.PreviewKeyUp += OnKeyUp;
            AssociatedObject.PreviewMouseLeftButtonDown += OnMouseLeftButtonDown;
            AssociatedObject.PreviewMouseLeftButtonUp += OnMouseLeftButtonUp;
            AssociatedObject.SelectionChanged += OnSelectionChanged;
            base.OnAttached();
        }

        protected override void OnDetaching()
        {
            AssociatedObject.PreviewKeyDown -= OnKeyDown;
            AssociatedObject.PreviewKeyUp -= OnKeyUp;
            AssociatedObject.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDown;
            AssociatedObject.PreviewMouseLeftButtonUp -= OnMouseLeftButtonUp;
            AssociatedObject.SelectionChanged -= OnSelectionChanged;
            base.OnDetaching();
        }

        private void OnMouseLeftButtonUp( object sender, MouseButtonEventArgs e )
        {
            m_expectingSelectionChanged = false;
        }

        private void OnKeyDown( object sender, KeyEventArgs e )
        {
            m_expectingSelectionChanged = true;
        }

        private void OnKeyUp( object sender, KeyEventArgs e )
        {
            m_expectingSelectionChanged = false;
        }

        private void OnMouseLeftButtonDown( object sender, MouseButtonEventArgs e )
        {
            m_expectingSelectionChanged = true;
        }

        private void OnSelectionChanged( object sender, SelectionChangedEventArgs e )
        {
            RaiseUserSelectionChangedEvent( new UserSelectionChangedEventArgs( UserSelectionChangedEvent, e, m_expectingSelectionChanged ) );
        }
    }

В XAML вы можете просто подписаться на UserSelectionChangedEvent следующим образом:

<ListBox ItemsSource="{Binding Items}"  b:UserSelectionChangedBehavior.UserSelectionChanged="OnUserSelectionChanged">
  <i:Interaction.Behaviors>
    <b:UserSelectionChangedBehavior/>
  </i:Interaction.Behaviors>

Обработчик:

private void OnUserSelectionChanged( object sender, UserSelectionChangedEventArgs e )
{
    if(e.SelectionChangedByUser)
    {
        Console.WriteLine( "Selection changed by user" );
    }
    else
    {
        Console.WriteLine( "Selection changed by code" );
    }
}

Это всего лишь идея. Возможно, вам даже не понадобится поведение, и вы просто определите прикрепленное перенаправленное событие. Но тогда я понятия не имею, где хранить флаг m_expectingSelectionChanged. Я также не знаю, работает ли это во всех случаях. Но, возможно, это даст вам отправную точку.

0 голосов
/ 07 февраля 2018

Обычно для Selector выбор устанавливается / изменяется при загрузке элемента управления в поле зрения.Когда это происходит, свойство IsLoaded по-прежнему false.Когда пользователь делает выбор вручную, элемент управления, очевидно, должен быть видимым, и, следовательно, IsLoaded будет true.Попробуйте использовать это свойство, чтобы определить, инициировано ли изменение пользователем или из-за загрузки элемента управления.

0 голосов
/ 16 января 2017

Вы можете проверить наличие добавленных элементов и удаленных элементов.Если он был инициирован пользователем, оба свойства имеют элемент.Если элемент был просто добавлен с помощью кода, список RemovedItems должен быть пустым.Поэтому

if (e.AddedItems.Count> 0 && e.RemovedItems.Count> 0) // Инициировано пользователем

0 голосов
/ 28 июня 2012

Почему ты хочешь знать?Я кодировал много диалогов, в которых у меня были похожие ситуации - я действительно не хотел знать, что пользователь использовал мышь или клавиатуру, но я действительно хотел определенного поведения, и я хотел, чтобы эффекты от запуска некоторой привязки вели себя правильно.

В большинстве случаев я обнаружил, что, используя шаблон MVVM - или, по крайней мере, отделяя логику от пользовательского интерфейса - вы часто избегаете этих проблем.

Так что для вашей проблемы я бы попытался исключить обработчик выбора и использовал только привязки - поэтому ваше состояние графического интерфейса основано на модели позади, а не на привязке событий.

mvvm:http://en.wikipedia.org/wiki/Model_View_ViewModel

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...