c# - 如何将双击绑定到列表框项
问题描述
我有两个包含集合的列表框。当前设置是,当在左侧列表框中选择一个项目时,您可以单击一个按钮以将该选定状态添加到右侧列表框中。列表框有一个添加和删除按钮,这些按钮与自定义命令相关联,列表框选定项是命令参数。
我想为每个框添加双击功能,以便可以双击项目来添加和删除。我应该能够使用我当前的命令执行方法来执行此操作,但还没有找到将其实现到列表框或列表框项中的解决方案。我想尽可能多地遵循 MVVM,但我已经用当前的执行方法稍微做了一点,如下所示,但任何帮助都将不胜感激。我没有找到任何关于我的具体问题的运气。
<ListBox x:Name="List" ItemContainerStyle="{StaticResource ListBoxItem}" DataContext="{StaticResource VM}"
ItemsSource="{Binding Names, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" DisplayMemberPath="Name"
Style="{StaticResource ResourceKey=ListBox}"/>
<Button Content=">>" Margin="5" Style="{StaticResource ResourceKey=MultiButton}"
CommandParameter="{Binding ElementName=List}"
Command="{Binding Path=AddSelectedItemCommand}"/>
public void AddSelectedItem(object obj)
{
ListBox ListBox = obj as ListBox;
List<Type> List = new List<Type>();
if (Name == null)
Name = new ObservableCollection<Type>();
if (Name != null)
{
foreach (Type item in ListBox.SelectedItems.Cast<object>().ToList())
{
List.Add(item);
Names.Remove(item);
}
foreach (Type listItem in List)
{
var state = Name.FirstOrDefault(aa => aa.Name == listItem.Name);
if (state == null)
{
Name.Add(listItem);
}
}
}
OnPropertyChanged("Name");
OnPropertyChanged("Names");
}
解决方案
首先我想让你知道你的视图模型应该对视图本身一无所知,所以它应该对列表框一无所知。
对象应该只知道它们所依赖的事物,而不是依赖它的事物。因此 ViewModel 应该只知道它提供给任何客户端的数据集合。
在您的示例中,当控件从 ListBox 更改时会发生什么 - 您将不得不更改您的命令。
所以,首先,你需要改变你的视图模型实现,你目前拥有的不是 MVVM。
这是一个完整的清单,可以帮助您一路走好:
<Window x:Class="WpfExample.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:WpfExample"
mc:Ignorable="d"
Title="MainWindow" Height="140" Width="410">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox ItemsSource="{Binding Path=Names, Mode=OneWay}"
SelectedItem="{Binding Path=SelectedName}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding .}">
<TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding Path=DataContext.MyDoubleClickCommand,
RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor} }" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox Grid.Column="1" Margin="10,0,0,0" ItemsSource="{Binding Path=NamesTwo, Mode=OneWay}"
SelectedItem="{Binding Path=SelectedNameTwo}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding .}">
<TextBlock.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding Path=DataContext.MyOtherDoubleClickCommand,
RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor} }" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
以及背后的代码
namespace WpfExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel();
}
}
}
然后是 ViewModel,你应该注意到它只修改了暴露给 View 消费的集合
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
using Prism.Commands;
namespace WpfExample
{
public class MyViewModel : INotifyPropertyChanged
{
private string _selectedName;
private string _selectedNameTwo;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ObservableCollection<string> Names { get; }
= new ObservableCollection<string>(new List<string>
{
"Name1",
"Name2",
"Name3",
"Name4",
"Name5"
});
public ObservableCollection<string> NamesTwo { get; } = new ObservableCollection<string>(new List<string>());
public string SelectedName
{
get { return _selectedName; }
set { _selectedName = value; OnPropertyChanged(); }
}
public string SelectedNameTwo
{
get { return _selectedNameTwo; }
set { _selectedNameTwo = value; OnPropertyChanged(); }
}
public ICommand MyOtherDoubleClickCommand
{
get
{
return new DelegateCommand<string>(name =>
{
NamesTwo.Remove(name);
Names.Add(name);
SelectedNameTwo = "";
});
}
}
public ICommand MyDoubleClickCommand
{
get
{
return new DelegateCommand<string>(name =>
{
Names.Remove(name);
NamesTwo.Add(name);
SelectedName = "";
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
我已经为 DelegateCommand 对象使用了 Prism.Core 包。这不是必需的,我只是为了方便
如果在处理 ViewModel 时不使用 SelectedName 和 SelectedNameTwo 属性,您甚至不需要它们。为了完整起见,我将它们包括在内。
.
编辑: 我最初没有注意到这是针对 UWP 项目的。我相信以下方法会起作用——尽管它在这里未经测试,因为我目前没有在我的机器上设置 UWP。我不确定
DoubleClick
EventName。
<Page xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:core="using:Microsoft.Xaml.Interactions.Core>
<ListBox Grid.Column="1" Margin="10,0,0,0" ItemsSource="{Binding Path=NamesTwo, Mode=OneWay}"
SelectedItem="{Binding Path=SelectedNameTwo}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding .}" >
<i:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="DoubleClick">
<core:InvokeCommandAction Command="{Binding Path=DataContext.MyDoubleClickCommand,
RelativeSource={RelativeSource AncestorType=Page, Mode=FindAncestor} }"
CommandParameter="{Binding .}" />
</core:EventTriggerBehavior>
</i:Interaction.Behaviors>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
推荐阅读
- python - 在python中安排5天的6天时间表
- android - 如何在主页片段中嵌入 YouTube 视频
- tensorflow - autokeras 模型转换为 tensorflowjs 模型
- python - 列表理解而不是嵌套的 for 循环
- monitoring - 如何显示前 K 个节点 wrt CPU 使用率?
- git - 使用 Github Actions 持续部署到 Heroku
- html - Gatsby 按钮 onClick 使用链接功能
- java - 将 onItemClickListener 放在 AutoCompleteTextView 下拉列表中并通过获取位置传递意图但失败
- javascript - Oribt 控件不起作用,鼠标无法移动场景
- android-popupwindow - 在另一个视图下方显示 Android 弹出窗口