MVVMの学習を始めました。私はこの MVVMチュートリアル (そこにいるすべてのMVVM初心者に強くお勧めします)に従ってアプリケーションをゼロから作成しました。基本的に、これまでに作成したのは、ユーザーが自分のデータを追加するテキストボックスと、そのデータを保存するボタンです。
ここで私は立ち往生しました:ListBoxItemをダブルクリックし、作成してViewModelに追加したコマンドをトリガーできるようにしたいのです。 XAML側を終了する方法がわかりません。つまり、そのコマンドをListBox(Item)にバインドする方法がわかりません。
XAMLは次のとおりです。
...
<ListBox
Name="EntriesListBox"
Width="228"
Height="208"
Margin="138,12,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
ItemsSource="{Binding Entries}" />
...
ViewModelは次のとおりです。
public class MainWindowViewModel : DependencyObject
{
...
public IEntriesProvider Entries
{
get { return entries; }
}
private IEntriesProvider entries;
public OpenEntryCommand OpenEntryCmd { get; set; }
public MainWindowViewModel(IEntriesProvider source)
{
this.entries = source;
...
this.OpenEntryCmd = new OpenEntryCommand(this);
}
...
}
最後に、ユーザーがEntriesListBoxのアイテムをダブルクリックしたときに実行するOpenEntryCommandを次に示します。
public class OpenEntryCommand : ICommand
{
private MainWindowViewModel viewModel;
public OpenEntryCommand(MainWindowViewModel viewModel)
{
this.viewModel = viewModel;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return parameter is Entry;
}
public void Execute(object parameter)
{
string messageFormat = "Subject: {0}\nStart: {1}\nEnd: {2}";
Entry entry = parameter as Entry;
string message = string.Format(messageFormat,
entry.Subject,
entry.StartDate.ToShortDateString(),
entry.EndDate.ToShortDateString());
MessageBox.Show(message, "Appointment");
}
}
助けてください、私はそれを感謝します。
残念ながら、ButtonBase
派生コントロールのみがICommand
オブジェクトをそれらのCommand
プロパティにバインドする可能性があります(Click
イベントの場合)。
ただし、Blendが提供するAPIを使用して、イベント(MouseDoubleClick
上のListBox
など)をICommand
オブジェクトにマッピングできます。
<ListBox>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding YourCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
以下を定義する必要があります:xmlns:i="http://schemas.Microsoft.com/expression/2010/interactivity"
およびSystem.Windows.Interactivity.dll
への参照があります。
-編集-これはWPF4の一部ですが、WPF4を使用していない場合は、Microsoft.Windows.Interactivityを使用できます。このdllはBlend SDKからのもので、Blendを必要としません。ここから http://www.Microsoft.com/downloads/en/details.aspx?FamilyID=f1ae9a30-4928-411d-970b-e682ab179e17&displaylang = en
更新:役に立つ何かを見つけました。 MVVM Light Toolkitのこのリンク を確認してください。これには、これを行う方法のチュートリアルと、必要なライブラリへの リンク が含まれています。 MVVM Light Toolkitは、MVVMをSilverlight、WPF、およびWP7に適用するための非常に興味深いフレームワークです。
お役に立てれば :)
これは、DoubleClickイベントのために注意が必要です。これを行うにはいくつかの方法があります。
2と3の方が純粋かもしれませんが、率直に言って、1は簡単で複雑ではなく、世界で最悪のものではありません。 1回限りのケースでは、おそらくアプローチ1を使用します。
ここで、たとえば各アイテムにハイパーリンクを使用するように要件を変更した場合は、より簡単になります。 XAMLでルート要素に名前を付けることから始めます-たとえば、Windowの場合:
<Window .... Name="This">
次に、ListBoxアイテムのDataTemplateで、次のようなものを使用します。
<ListBox ...>
<ListBox.ItemTemplate>
<DataTemplate>
<Hyperlink
Command="{Binding ElementName=This, Path=DataContext.OpenEntryCmd}"
Text="{Binding Path=Name}"
/>
ElementNameバインディングを使用すると、特定のデータ項目ではなく、ViewModelのコンテキストからOpenEntryCmdを解決できます。
これを行う最善の方法は、コマンドとパラメーターの依存関係プロパティを使用して、コンテンツの単純なユーザーコントロールラッパーを作成することです。
これを行った理由は、ButtonがクリックイベントをListBoxにバブリングせず、ListBoxItemを選択できなかったためです。
CommandControl.xaml.cs:
public partial class CommandControl : UserControl
{
public CommandControl()
{
MouseLeftButtonDown += OnMouseLeftButtonDown;
InitializeComponent();
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
if (Command != null)
{
if (Command.CanExecute(CommandParameter))
{
Command.Execute(CommandParameter);
}
}
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand),
typeof(CommandControl),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object),
typeof(CommandControl),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None));
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
}
CommandControl.xaml:
<UserControl x:Class="WpfApp.UserControls.CommandControl"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.Microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Background="Transparent">
</UserControl>
使用法:
<ListBoxItem>
<uc:CommandControl Command="{Binding LoadPageCommand}"
CommandParameter="{Binding HomePageViewModel}">
<TextBlock Text="Home" Margin="0,0,0,5" VerticalAlignment="Center"
Foreground="White" FontSize="24" />
</uc:CommandControl>
</ListBoxItem>
コンテンツは何でもかまいません。コントロールをクリックすると、コマンドが実行されます。
編集:追加Background="Transparent"
をUserControlに追加して、コントロールの領域全体でクリックイベントを有効にします。
これはちょっとしたハックですが、うまく機能し、コマンドを使用してコードビハインドを回避できます。これには、ScrollView
がコンテナ全体を満たさないと仮定して、空のListBoxItems
エリアでダブルクリック(またはトリガーが何であれ)してもコマンドをトリガーしないという利点もあります。
基本的に、DataTemplate
で構成されるListBox
のTextBlock
を作成し、TextBlock
の幅をListBox
、マージンとパディングを0に設定し、水平スクロールを無効にします(TextBlock
がScrollView
の表示範囲を超えて出血するため、水平スクロールバーがトリガーされます)。私が見つけた唯一のバグは、ユーザーがListBoxItem
の境界線を正確にクリックしてもコマンドが実行されないことです。
以下に例を示します。
<ListBox
x:Name="listBox"
Width="400"
Height="150"
ScrollViewer.HorizontalScrollBarVisibility="Hidden"
ItemsSource="{Binding ItemsSourceProperty}"
SelectedItem="{Binding SelectedItemProperty}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Padding="0"
Margin="0"
Text="{Binding DisplayTextProperty}"
Width="{Binding ElementName=listBox, Path=Width}">
<TextBlock.InputBindings>
<MouseBinding
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}, Path=DataContext.SelectProjectCommand}"
Gesture="LeftDoubleClick" />
</TextBlock.InputBindings>
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>