私はMVVMを使用しています。2つのリストビューがあります。最初のリストビューは問題ありません。データを入力できます。IEnuerableです。私が達成したいのは、最初のリストビューの項目(行)をクリックしたときに、選択したものを2番目のリストビューに追加したいということです。誰でもこれについてアドバイスできますか?
3 に答える
MVVMを使用してやりたいことを行う方法を示すためItemViewModel
に、リストビューにアイテムを表すものがあると仮定します。ListView.ItemTemplate
各アイテムを適切にレンダリングするようにを設定する必要があります(または、ToString
メソッドをオーバーライドしてアイテムの文字列表現を返す)。
MainViewModel
次の3つのプロパティが必要です。
Items1
アイテムのリストが含まれています。この例では、リストは更新されていないためIEnumerable<ItemViewModel>
、十分です。SelectedItem1
これは、最初のリストビュー(存在する場合)で現在選択されているアイテムを参照します。Items2
これまでに選択したアイテムのリストが含まれています。このリストが更新されるため、ObservableCollection<ItemViewModel>
使用されます。
の唯一の興味深いコードMainViewModel
は、のセッターですSelectedItem1
。これは、最初のリストビューでの選択が変更されるたびに変更されます。これが発生すると、選択したアイテムがコレクションに追加されますItems2
。
public class MainViewModel {
ItemViewModel selectedItem1;
public MainViewModel(IEnumerable<ItemViewModel> items1) {
Items1 = items1;
Items2 = new ObservableCollection<ItemViewModel>();
}
public IEnumerable<ItemViewModel> Items1 { get; private set; }
public ObservableCollection<ItemViewModel> Items2 { get; private set; }
public ItemViewModel SelectedItem1 {
get { return this.selectedItem1; }
set {
this.selectedItem1 = value;
if (this.selectedItem1 != null && !Items2.Contains(this.selectedItem1))
Items2.Add(this.selectedItem1);
}
}
}
INotifyPropertyChanged
この例では必要ないため、この単純なビューモデルは実装されていないことに注意してください。
ビューは、次のようにXAMLを使用してビューモデルにバインドされます(たとえば、DataContext
このXAMLを含むものはすべてのインスタンスに設定する必要がありますMainViewModel
)。
<StackPanel>
<ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
<ListView ItemsSource="{Binding Items2}"/>
</StackPanel>
1つ目は、ビューモデルでListView
バインドされます。Items1
での選択ListView
が変更されると、データバインディングSelectedItem1
により、ビューモデルで設定されていることが保証されます。次に、セッターのコードがItems2
プロパティを更新します。これはObservableCollection<T>
新しいアイテムであるため、追加されたアイテムはデータバインディングを使用してプッシュされます(この場合は2番目に)ListView
。
ListView
あなたの場合、プロパティをバインドすることで、で選択イベントを処理することができSelectedItem
ます。ただし、データバインディングを使用して「イベントを処理」することが不可能な場合があります。解決策は、ビューのコードビハインドにイベントハンドラーを追加することですが、これにより、ビューモデルとビューの間に望ましくない依存関係が生じることがよくあります。代わりに、ブレンド動作を使用できます。独自のBehavior
クラスを作成することで、イベントを処理し、データバインドできるものに変換して、不要な依存関係を解消できます。ただし、特定の問題を解決するためにそれは必要ありません。
Behavior
を使用する場合は、BlendSDKは不要であることに注意してください。NuGetを使用して依存関係Blend.Interactivity.Wpf
(またはフレームワークによっては同様のパッケージ)を追加し、BlendBehaviorsを使用するために必要な単一のDLLを取得できます。
したがって、クリックされたときに2番目のリストからアイテムの選択を解除する方法を拡張するには、ビヘイビアーを使用する必要があります。SelectedItem
2番目にバインドされたプロパティのセッターでアクションが実行される上記と同じトリックを使用しようとするListView
と失敗します。2番目に新しいアイテムを追加するとListView
すぐにこのアイテムが選択され、すぐに新しく追加されたアイテムが削除されるためです。あなたが望むものではありません。
これは、MouseLeftButtonUpBehavior
コードビハインドなしで、コントロール上でマウスの左ボタンを離したときにコマンドを実行できるようにするものです。
class MouseLeftButtonUpBehavior : Behavior<Control> {
public static readonly DependencyProperty CommandProperty
= DependencyProperty.Register(
"Command",
typeof(ICommand),
typeof(MouseLeftButtonUpBehavior)
);
public ICommand Command
{
get { return (ICommand) GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
protected override void OnAttached() {
AssociatedObject.MouseLeftButtonUp += OnMouseLeftButtonUp;
}
protected override void OnDetaching() {
AssociatedObject.MouseLeftButtonUp -= OnMouseLeftButtonUp;
}
void OnMouseLeftButtonUp(Object sender, MouseButtonEventArgs mouseButtonEventArgs) {
if (Command != null)
Command.Execute(mouseButtonEventArgs);
}
}
XAMLをこれに変更する必要があります(NuGetを使用してBlend.Interactivity.Wpf
パッケージへの参照を追加し、コントロールにインタラクションを追加できるようにすることができます)。
<StackPanel>
<ListView ItemsSource="{Binding Items1}" SelectedItem="{Binding SelectedItem1}"/>
<ListView ItemsSource="{Binding Items2}" SelectedItem="{Binding SelectedItem2}">
<i:Interaction.Behaviors>
<local:MouseLeftButtonUpBehavior Command="{Binding DeselectCommand}"/>
</i:Interaction.Behaviors>
</ListView>
</StackPanel>
ビューモデルには、次の2つの新しいプロパティが必要です。
public ItemViewModel SelectedItem2 { get; set; }
public ICommand DeselectCommand { get; private set; }
はSelectedItem2
、2番目のリストビューで選択されているアイテムを追跡するために使用されます。はDeselectCommand
、2番目のリストビューでマウスの左ボタンアップイベントが発生したときに実行されます。実際に何か便利なことをするには、コマンドを作成する必要があります。を使用できますDelegateCommand
。このクラスはWPFの一部ではありませんが、グーグルで検索すると、適切な実装を簡単に見つけることができます。Aは、選択したデリゲートを実行するDelegateCommand
WPFを作成する方法にすぎません。ICommand
のコンストラクターでMainViewModel
:
DeselectCommand = new DelegateCommand(_ => Deselect());
そして、あなたはで実装する必要がありDeselect
ますMainViewModel
:
void Deselect() {
if (SelectedItem2 != null)
Items2.Remove(SelectedItem2);
}
これらすべてをまとめると、クリックされたときに2番目のリストビューからアイテムが削除されます。これにより、ビューにコードビハインドがなく、ビューからビューモデルへの不要な依存関係が作成される可能性があります(たとえば、ビューのコードはDeselect
ビューモデルを呼び出す必要があることを知っています)。
panel / convas / gridに2つのリストビューを追加し、このコードを追加します。listView1のSelectionChangedイベント(イベントハンドラーlistView1_SelectionChanged)を必ず登録してください。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void listView1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
listView2.Items.Add((listView1.SelectedItem));
}
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
listView1.Items.Add("test 1");
listView1.Items.Add("test 2");
}
}
}
SelectionChangedイベントを使用します。その後、あなたは次のようなことをすることができます
Listview2.Items.Add(Listview1.SelectedItem);