简体   繁体   中英

How to support ListBox SelectedItems binding with MVVM in a navigable application

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

I am making a WPF application that is navigable via custom "Next" and "Back" buttons and commands (ie not using a NavigationWindow ). On one screen, I have a ListBox that has to support multiple selections (using the Extended mode). I have a view model for this screen and store the selected items as a property, since they need to be maintained.

However, I am aware that the SelectedItems property of a ListBox is read-only. I have been trying to work around the issue using this solution here , but I have not been able to adopt it into my implementation. I found that I can't differentiate between when one or more elements are deselected and when I navigate between screens ( NotifyCollectionChangedAction.Remove is raised in both cases, since technically all the selected items are deselected when navigating away from the screen). My navigation commands are located in a separate view model which manages the view models for each screen, so I can't put any implementation related to the view model with the ListBox in there.

I have found several other less elegant solutions, but none of these seem to enforce a two-way binding between the view model and the view.

Any help would be greatly appreciated. I can provide some of my source code if it would help to understand my problem.

It took me a while to implement binding/using SelectedItems as I am not an expert at this so I wanted to share my solution if someone might find it useful. Do not forget to download Microsoft.Xaml.Behaviors.Wpf from Nuget for this solution.

I have benefited from Accessing WPF ListBox SelectedItems

View:

Window x:Class="WpfAppSelectedItems.MainWindow"
        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"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors" 
        xmlns:local="clr-namespace:WpfAppSelectedItems"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    
    <Grid>
        <ListBox Height="250" Width="300"
            ItemsSource="{Binding Items}" SelectionMode="Extended"
            >
            <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Setter Property="IsSelected" Value="{Binding IsSelected}" />
                </Style>
            </ListBox.ItemContainerStyle>

            <ListBox.InputBindings>
                <KeyBinding Gesture="Ctrl+A" Command="{Binding SelectAllCommand}" />
            </ListBox.InputBindings>

            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged" >
                    <i:CallMethodAction TargetObject="{Binding}" MethodName="ListBox_SelectionChanged"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ListBox>

    </Grid>
</Window>

`

Code behind:

namespace WpfAppSelectedItems
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel(); //connecting window to VM
        }
    }
}

ViewModel:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.Xaml.Behaviors;
using System.Windows;

namespace WpfAppSelectedItems
{
    internal class ViewModel: Presenter
    {
        //Creating ItemPresenter class. IsSelected binded to Style in the view
        public class ItemPresenter : Presenter
        {
            private readonly string _value;

            public ItemPresenter(string value)
            {
                _value = value;
            }

            public override string ToString()
            {
                return _value;
            }

            private bool _isSelected;
            public bool IsSelected
            {
                get { return _isSelected; }
                set
                {
                    _isSelected = value;
                    OnPropertyChanged();
                }
            }
        }

        //Placing items to the Items which is binded to the ListBox 
        public ObservableCollection<ItemPresenter> Items { get; } = new ObservableCollection<ItemPresenter>
        {
            new ItemPresenter("A"),
            new ItemPresenter("B"),
            new ItemPresenter("C"),
            new ItemPresenter("D")
        };

        //Do something when selection changed including detecting SelectedItems
        public void ListBox_SelectionChanged()
        {
            foreach (var item in Items)
            {
                if (item.IsSelected)
                    MessageBox.Show(fufuitem.ToString());
                    
            }
        }
    };

    //Notify View if a property changes
    public abstract class Presenter : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

if you just want to get the Name of the selected Element you can do the following:

View:

<ListBox
    x:Name="Folders"
    Grid.Row="1"
    Grid.Column="0"
    ItemsSource="{Binding YourListWithStings}"
    SelectionMode="Single"
    SelectedItem="{Binding ToYourOutputVariable}"
    >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Viewmodel:

private string _ToYourOutputVariable
public string ToYourOutputVariable
{
    get {return _ToYourOutputVariable; }
    set 
       {
          _ToYourOutputVariable = value;
          NotifyOfPropertyChange(); 
          MessageBox.Show(_ToYourOutputVariable);
       }
}

The messageBox shows the name of the selected listitem. You could call a function where you open the MessageBox

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM