首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >WPF中的EventTrigger

WPF中的EventTrigger
EN

Stack Overflow用户
提问于 2019-08-23 15:40:03
回答 1查看 450关注 0票数 0

我希望从列表框中获取SelectedItems,其中通过InvokeCommandAction选择复选框,并将其存储在obsevableCollection SelectedItems中,但无法使SelectedItemChangedCommand正常工作(断点未命中),也不确定如何填充SelectedItems集合中的项。我试过这样做,希望一旦选中或未选中复选框,就会调用SelectedItemChangedCommand,并且可以在此调用一个方法,在其中填充SelectedItems。

请注意,我正在寻找一种方法来实现这一点,没有任何代码背后。

代码语言:javascript
复制
 <ListBox Margin="45,7,0,0" VerticalAlignment="Top" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2"
         ItemsSource="{Binding ListItems}"
         SelectionMode="Multiple" Height="146">
    <ListBox.Resources>
        <Style TargetType="ListBoxItem">
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <CheckBox Margin="5,2"
                                  IsChecked="{TemplateBinding IsSelected}">
                            <ContentPresenter />
                        </CheckBox>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.Resources>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"  CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListBox>

更新的Xaml文件

代码语言:javascript
复制
<Window x:Class="stack.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:local="clr-namespace:stack"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Grid>
        <ListBox x:Name="myListBox" Margin="45,7,0,0" VerticalAlignment="Top" 

                 ItemsSource="{Binding ListItems}"
                 SelectionMode="Multiple" Height="146">
            <ListBox.Resources>
            <Style TargetType="ListBoxItem">
                <Setter Property="OverridesDefaultStyle" Value="true" />
                <Setter Property="SnapsToDevicePixels" Value="true" />
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListBoxItem">
                            <CheckBox 
                                Margin="5,2" 
                                IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}" 
                            >
                                <ContentPresenter />
                            </CheckBox>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListBox.Resources>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <i:InvokeCommandAction Command="{Binding SelectedItemChangedCommand}"  
                                       CommandParameter="{Binding ElementName=myListBox, Path=SelectedItem}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
        </ListBox>
    </Grid>
</Window>

我将列表框绑定到视图模型中定义为observableCollection ListItems的

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace stack
{


    public class MainViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<string> ListItems { get; set; }
        public ObservableCollection<string> SelectedListItems { get; set; }

        public RelayCommand SelectedItemChangedCommand { get; set; }

        public string _selectedItem;
        public string SelectedItem
        {
            get => _selectedItem;
            set
            {
                _selectedItem = value;
                OnPropertyChanged("SelectedItem");
            }
        }

        public bool _isSelected;
        public bool IsSelected
        {
            get => _isSelected;
            set
            {
                _isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }

        public MainViewModel()
        {
            ListItems = new ObservableCollection<string>();
            ListItems.Add("One");
            ListItems.Add("Two");
            ListItems.Add("three");
            ListItems.Add("Four");
            ListItems.Add("Five");
            SelectedItemChangedCommand = new RelayCommand(this.ExecuteItemChanged);
        }

        public void ExecuteItemChanged(object parameter)
        {
            if (IsSelected)
            {
                SelectedListItems.Add(SelectedItem);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler _propertyChangedEventHandler = PropertyChanged;
            _propertyChangedEventHandler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-08-23 16:07:23

TemplateBinding很便宜,但它不进行双向绑定。因此,项目没有被选中。您需要与RelativeSource of TemplatedParent定期绑定。

代码语言:javascript
复制
<CheckBox 
    Margin="5,2" 
    IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}" 
    >

请注意,您正在将CheckBox.IsChecked绑定到ListBoxItem.IsSelected。模板的父版本是一个ListBoxItem,而不是您的主要视图模型。

其次,您希望将SelectedItems、复数属性传递给您的命令。SelectedItem是单数的。只有一个项目。这将是最上面选择的项目时,许多被选中。您的列表框中有SelectionMode="Multiple“,所以我假设您想要完整的选择。

代码语言:javascript
复制
<i:InvokeCommandAction 
    Command="{Binding SelectedItemChangedCommand}" 
    CommandParameter="{Binding ElementName=myListBox, Path=SelectedItems}"
    />

并确保x:Name="myListBox"在ListBox上: CommandParameter绑定需要这样才能找到SelectedItems。

最后: ExecuteItemChanged()非常坏。您的主要视图模型属性IsSelectedSelectedItem没有绑定到任何东西。它们一直都是假的和空的。每次选择更改时,都执行命令并将第一个选定项作为parameter传递,然后忽略它,然后查看false是否仍然是false,它是false。如果不是,则视图模型的SelectedItem属性仍然为空,因为您也从未更新过该属性。

下面是您想要做的事情:当选择更改时,将当前选定项的整个集合传递到您的命令中。用控件中的当前状态替换视图模型当前选定项的整个集合。您必须、必须将SelectedItems绑定为上面的CommandParameter。

去掉视图模型上的SelectedItemIsSelected,它们就没有用了。

如果可能的话,千万不要参与维护两个列表并试图让它们零散地保持同步的工作。总是一团糟。在这种情况下你不需要这么做。

代码语言:javascript
复制
public void ExecuteItemChanged(object parameter)
{
    //  ListBox.SelectedItems is System.Windows.Controls.SelectedItemCollection,
    //  a precambrian monster that's declared internal in PresentationFramework.dll. 
    //  However, it does implement non-generic IList, so cast it to that. 
    if (parameter is System.Collections.IList selectedItems)
    {
        if (SelectedListItems == null)
        {
            SelectedListItems = new ObservableCollection<String>();
        }

        SelectedListItems.Clear();

        foreach (string item in selectedItems)
        {
            SelectedListItems.Add(item);
        }
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57629381

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档