WPF MVVM ListBox 中的多项选择

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34630406/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 13:36:52  来源:igfitidea点击:

Multiple selection in WPF MVVM ListBox

wpfmvvmlistboxcaliburn.micromultipleselection

提问by Michal

I have a ListBox containing filenames. Now I need to get array of selected items from this ListBox. I found a few answers here, but none of them worked for me. I'am using Caliburn Micro framework.

我有一个包含文件名的 ListBox。现在我需要从这个 ListBox 中获取所选项目的数组。我在这里找到了一些答案,但没有一个对我有用。我正在使用 Caliburn Micro 框架。

Here is my View:

这是我的观点:

<Window x:Class="ProgramsAndUpdatesDesktop.Views.DeleteHistoryView"
    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:local="clr-namespace:ProgramsAndUpdatesDesktop.Views"
    mc:Ignorable="d"
    ResizeMode="CanResizeWithGrip"
    MaxWidth="300"
    MinWidth="300"
    MinHeight="500"
    Title="DeleteHistoryView" Height="500" Width="300">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="30" />
    </Grid.RowDefinitions>
    <StackPanel Grid.Column="0" Grid.Row="0">
        <ListBox x:Name="DeleteHistoryListBox" SelectedItem="{Binding Path=DeleteHistorySelectedItem}" 
                 ItemsSource="{Binding DeleteHistoryListBox, NotifyOnSourceUpdated=True}" 
             SelectionMode="Multiple">
        </ListBox>
    </StackPanel>
    <StackPanel Grid.Column="0" Grid.Row="1">
        <Button x:Name="DeleteHistoryButtonAction">Delete</Button>
    </StackPanel>
</Grid>

And here is my ViewModel:

这是我的 ViewModel:

class DeleteHistoryViewModel : Screen
{
    string historyFolderPath = Environment.ExpandEnvironmentVariables(ConfigurationManager.AppSettings["HistoryFolderPath"]);

    private ObservableCollection<string> deleteHistoryListBox = new ObservableCollection<string>();
    public ObservableCollection<string> DeleteHistoryListBox
    {
        get { return deleteHistoryListBox; }
        set { deleteHistoryListBox = value; NotifyOfPropertyChange(() => DeleteHistoryListBox); }
    }

    private List<string> deleteHistorySelectedItem = new List<string>();
    public List<string> DeleteHistorySelectedItem
    {
        get { return deleteHistorySelectedItem; }
        set { deleteHistorySelectedItem = value; }
    }

    public DeleteHistoryViewModel()
    {
        base.DisplayName = "Delete History";
    }

    protected override void OnInitialize()
    {
        FillListBox();
    }

    private void FillListBox()
    {
        string[] directory = Directory.GetFiles($"{historyFolderPath}\", "*.json");

        foreach (var item in directory)
        {
            string fileName = System.IO.Path.GetFileName(item).ToString();
            if (!DeleteHistoryListBox.Contains(fileName))
            {
                DeleteHistoryListBox.Add(fileName);
            }
        }
    }

    #region ACTIONS REGION

    // DELETE HISTORY ACTION
    public void DeleteHistoryButtonAction()
    {
        foreach (var item in DeleteHistorySelectedItem)
        {
            MessageBox.Show(item);
        }
    }

    #endregion

}

回答by Justin CI

You can use this code for MVVM Pattern

您可以将此代码用于 MVVM 模式

XAML

XAML

<ListBox x:Name="DeleteHistoryListBoxItem" SelectedItem="{Binding Path=DeleteHistorySelectedItem,UpdateSourceTrigger=PropertyChanged}" 
         ItemsSource="{Binding DeleteHistoryListBox, NotifyOnSourceUpdated=True}" SelectionMode="Multiple">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Item}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}"/>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

ViewModel

视图模型

private ObservableCollection<HistoryItems> deleteHistoryListBox = new ObservableCollection<HistoryItems>();
public ObservableCollection<HistoryItems> DeleteHistoryListBox
{
    get
    {
        return deleteHistoryListBox;
    }
    set
    {
        deleteHistoryListBox = value;
        this.RaisePropertyChanged("DeleteHistoryListBox");
    }
}

private HistoryItems deleteHistorySelectedItem;
public HistoryItems DeleteHistorySelectedItem
{
    get
    {
        return deleteHistorySelectedItem;
    }
    set
    {
        var selectedItems = DeleteHistoryListBox.Where(x => x.IsSelected).Count();
        this.RaisePropertyChanged("DeleteHistorySelectedItem");
    }
}

Class

班级

public class HistoryItems : INotifyPropertyChanged
{
    private string item;

    public string Item
    {
        get { return item; }
        set
        {
            item = value;
            this.RaisePropertyChanged("Item");
        }
    }

    private bool isSelected;

    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            isSelected = value;
            this.RaisePropertyChanged("IsSelected");
        }
    }
}

回答by Anton Danylov

You can add SelectionChanged event handler in code-behind, and update property for selected items in the ViewModel from there.

您可以在代码隐藏中添加 SelectionChanged 事件处理程序,并从那里更新 ViewModel 中所选项目的属性。

XAML:

XAML:

    <ListBox x:Name="DeleteHistoryListBox" SelectedItem="{Binding Path=DeleteHistorySelectedItem}" 
             ItemsSource="{Binding DeleteHistoryListBox, NotifyOnSourceUpdated=True}" 
         SelectionMode="Multiple" SelectionChanged="DeleteHistoryListBox_SelectionChanged">
    </ListBox>

DeleteHistoryView.xaml.cs

删除历史视图.xaml.cs

private void DeleteHistoryListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
        DeleteHistoryViewModel vm = (DeleteHistoryViewModel)DataContext;

        foreach (string item in e.AddedItems)
        {
            vm.DeleteHistorySelectedItem.Add(item);
        }

        foreach (string item in e.RemovedItems)
        {
            vm.DeleteHistorySelectedItem.Remove(item);
        }
}