WPF ListBox SelectedItems определя Ctrl или Shift, натиснати за избор

Трябва да знам дали SelectedItems са били запълнени при натискане на Ctrl или Shift или не. Има ли лесен начин (без създаване на нов контролен шаблон) да получите тази информация? Предпочитам решения без код.

С най-добри пожелания Яник


person Yannik    schedule 28.04.2015    source източник
comment
Защо се нуждаете от тази информация? Просто задайте SelectionMode на MultiExtended и вашите SelectedItems ще бъдат запълнени.   -  person Michi-2142    schedule 28.04.2015
comment
Трябва да събера избрани елементи от различни дъщерни модели на изглед и в основния модел на изглед искам да действам спрямо избора на всички дъщерни модели на изглед. Ако е избран само един елемент (във всички модели дъщерни изгледи), действам различно от това, когато са избрани няколко елемента. Селекциите в дъщерните модели на изглед са обвързани с персонализирана ObservableCollection, която е обвързана с SelectedItems на ListBox.   -  person Yannik    schedule 28.04.2015


Отговори (2)


Можете да свържете събитието за промяна на избора и да проверите дали са натиснати модификаторните клавиши за избор.

    void listBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var isCtrlorShiftDown = (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl) || Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift));
        if (isCtrlorShiftDown)
        {
            // Write your Logic Here;
        }
    }
person Arun Selva Kumar    schedule 28.04.2015
comment
Благодаря, но точно това е задният код, който не искам да използвам:-) - person Yannik; 30.04.2015

Намерих решение с минимален код.

Основната концепция е, че прикачвам събитията KeyDown и KeyUp в MainWindow и задавам свойство „CurrentKeyboardKeyPressed“ на MainViewModel, което разпространява информацията за натиснатия клавиш към моделите на дъщерния изглед, които от своя страна задействат персонализирано събитие със специален Selection клас, който има информация за текущо натиснатия клавиш.

Публикуваният изходен код е силно съкратен и изобщо не работи. Ако някой се интересува от работещото решение, просто ме попитайте и ще го изпратя по имейл.

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    private readonly MainWindowViewModel _mainWindowViewModel;

    public MainWindow()
    {
        _mainWindowViewModel = new MainWindowViewModel();
        InitializeComponent();

        DataContext = _mainWindowViewModel;
    }

    private void MainWindow_OnKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.LeftCtrl || e.Key == Key.RightCtrl)
        {
            _mainWindowViewModel.CurrentKeyboardKeyPressed = PressedKeyboardKey.Ctrl;
            return;
        }

        if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
        {
            _mainWindowViewModel.CurrentKeyboardKeyPressed = PressedKeyboardKey.Shift;
        }
    }

    private void MainWindow_OnKeyUp(object sender, KeyEventArgs e)
    {
        _mainWindowViewModel.CurrentKeyboardKeyPressed = PressedKeyboardKey.None;
    }
}

MainWindowViewModel.cs

public class MainWindowViewModel : ViewModelBase
{
    // child view models
    private readonly ObservableCollection<TTSViewModel> _ttsViewModels;

    private PressedKeyboardKey _currentKeyboardKeyPressed;

    public EventHandler<KeyboardKeyPressedEventArgs> CurrentKeyboardKeyPressedChanged;

    public MainWindowViewModel()
    {
        _ttsViewModels = new ObservableCollection<TTSViewModel>();
    }

    public PressedKeyboardKey CurrentKeyboardKeyPressed
    {
        get { return _currentKeyboardKeyPressed; }
        set
        {
            if (_currentKeyboardKeyPressed != value)
            {
                _currentKeyboardKeyPressed = value;
                OnCurrentKeyboardKeyPressedChanged(_currentKeyboardKeyPressed);
            }
        }
    }

    // create child view models
    public void PopulateTTSList(int itemsToCreated)
    {
        for (int i = 0; i < itemsToCreated; i++)
        {
            var tts = new TTSViewModel("TTS " + i);

            tts.FractionSelectionChanged += OnTTSFractionSelectionChanged;
            CurrentKeyboardKeyPressedChanged += tts.CurrentKeyboardKeyPressedChanged;
            _ttsViewModels.Add(tts);
        }
    }

    private void OnCurrentKeyboardKeyPressedChanged(PressedKeyboardKey currentKeyboardKeyPressed)
    {
        var handler = CurrentKeyboardKeyPressedChanged;
        if (handler != null)
        {
            handler(this, new KeyboardKeyPressedEventArgs(currentKeyboardKeyPressed));
        }
    }

    // selection changed handler for each child view model
    private void OnTTSFractionSelectionChanged(object sender, ItemSelectionChangedEventArgs fractionSelectionChangedEventArgs)
    {
        var sendingTTS = sender as TTSViewModel;
        if (fractionSelectionChangedEventArgs.Selection.PressedKeyOnSelection == PressedKeyboardKey.None)
        {
            // single selection action goes here
            // ....
        }
        else
        {
            // multi selection action goes here
            // ....
        }
    }
}

TTSViewModel.cs (модел на дъщерен изглед)

public class TTSViewModel : ViewModelBase
{
    private readonly SmartObservableCollection<FractionViewModel> _currentlySelectedfractions;
    public EventHandler<ItemSelectionChangedEventArgs> FractionSelectionChanged;
    private PressedKeyboardKey _currentKeyboardKeyPressed;

    public TTSViewModel()
    {
        _currentlySelectedfractions = new SmartObservableCollection<FractionViewModel>();
        _currentlySelectedfractions.CollectionChanged += CurrentlySelectedfractionsOnCollectionChanged;
    }

    public void CurrentKeyboardKeyPressedChanged(object sender, KeyboardKeyPressedEventArgs currentKeyboardKeyPressedEventArgs)
    {
        _currentKeyboardKeyPressed = currentKeyboardKeyPressedEventArgs.CurrentKeyboardKeyPressed;
    }

    private void CurrentlySelectedfractionsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
    {
        if (FractionSelectionChanged != null)
        {
            if (notifyCollectionChangedEventArgs.Action == NotifyCollectionChangedAction.Replace && notifyCollectionChangedEventArgs.NewItems != null)
            {
                var removed = _oldSelectedfractions.Except(_currentlySelectedfractions);
                var added = _currentlySelectedfractions.Except(_oldSelectedfractions);

                var selection = new Selection<FractionViewModel>(added, removed, _currentKeyboardKeyPressed);

                _oldSelectedfractions.Clear();
                foreach (var currentlySelectedfraction in _currentlySelectedfractions)
                {
                    _oldSelectedfractions.Add(currentlySelectedfraction);
                }

                var selectionChangedArgs = new ItemSelectionChangedEventArgs(selection);
                FractionSelectionChanged(this, selectionChangedArgs);
            }
        }
    }
}

Selection.cs

public sealed class Selection<T>
{
    private readonly List<T> _added;
    private readonly List<T> _removed;
    private readonly PressedKeyboardKey _currentKeyboardKeyPressed;

    public Selection()
    {
        _added = new List<T>();
        _removed = new List<T>();
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="Selection{T}" /> class.
    /// </summary>
    /// <param name="addedItems">[NotNull]</param>
    /// <param name="removedItems">[NotNull]</param>
    /// <param name="currentKeyboardKeyPressed">The current keyboard key pressed.</param>
    public Selection(IEnumerable<T> addedItems, IEnumerable<T> removedItems, PressedKeyboardKey currentKeyboardKeyPressed)
    : this()
    {
        _added.AddRange(addedItems);
        _removed.AddRange(removedItems);
        _currentKeyboardKeyPressed = currentKeyboardKeyPressed;
    }

    public IReadOnlyList<T> Added
    {
        get { return _added; }
    }

    public IReadOnlyList<T> Removed
    {
        get { return _removed; }
    }

    public PressedKeyboardKey PressedKeyOnSelection
    {
        get { return _currentKeyboardKeyPressed; }
    }
}

KeyboardKeyPressedEventArgs.cs

public sealed class KeyboardKeyPressedEventArgs : EventArgs
{
    public KeyboardKeyPressedEventArgs(PressedKeyboardKey currentKeyboardKeyPressed)
    {
        CurrentKeyboardKeyPressed = currentKeyboardKeyPressed;
    }

    public PressedKeyboardKey CurrentKeyboardKeyPressed { get; private set;     }
}

ItemSelectionChangedEventArgs.cs

public sealed class ItemSelectionChangedEventArgs : EventArgs
{
    public ItemSelectionChangedEventArgs(Selection<FractionViewModel> newSelection)
    {
        Selection = newSelection;
    }

    public Selection<FractionViewModel> Selection { get; private set; }
}

PressedKeyboardKey.cs

public enum PressedKeyboardKey
{
    None,
    Ctrl,
    Shift
}
person Yannik    schedule 28.04.2015