以前はVS addinにあった機能のVSパッケージ拡張を開発中です。WPF - Listbox項目の2つのコマンド
アドインはツールバーのウィンドウにファイルをロードし、ユーザがアイテム(ファイルの名前)をダブルクリックすると、ファイルはVSのエディタで開きます。ユーザが右クリックした場合アイテムにポップアップメニューが表示されます。ですから、私の質問は、リストボックス項目のこれらのアクション(ダブルクリックと右クリック)を既存のコードと結びつけるのが最善の方法です。
私たちはWPFを使用していますが、アドインの場合はWindowsフォームでした。 しかし、私はWPFにあまり慣れていません。約1年前、私はブライアン・ノイエスのPluralsightコース「WPF MVVM In Depth」を見て、エクステンションにいくつかのことを実装しましたが、今年のほとんどの期間、エクステンションに取り組んでいません。結果は、私が書いたコードの曖昧な想い出しか持たないということです。私は、最高のデザインが何であるかについてちょっと混乱しています。
だから、私は私がすでに持っているものをお見せしましょう:
ここでXAMLファイルされる:
<UserControl x:Class="Sym.VisualStudioExtension.Engines.TAEngineView"
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"
xmlns:behaviours="clr-namespace:Sym.VisualStudioExtension"
xmlns:local="clr-namespace:Sym.VisualStudioExtension"
local:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="700" d:DesignWidth="400">
<Grid>
<TabControl x:Name="tabControl" HorizontalAlignment="Left" Height="490" Margin="19,44,-36,-234" VerticalAlignment="Top" Width="317">
<TabItem Header="Parameter Files">
<ListBox Margin="20" ItemsSource="{Binding ParameterFilesList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
<TabItem Header="Calc Files">
<ListBox Margin="20" ItemsSource="{Binding CalcFilesList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
</TabControl>
<Label x:Name="label" Content="{Binding Path=Title}" HorizontalAlignment="Left" Margin="19,13,0,0" VerticalAlignment="Top" Width="367
" BorderThickness="2"/>
</Grid>
CalcFilesListはタイプObservableCollection<CalcFile>
のものであり、タイプObservableCollection<Parameter>
のParameterFilesList。
その後、私はすでにこのRelayCommandクラスを持っている:
using System;
using System.Diagnostics;
using System.Windows.Input;
namespace Sym.VisualStudioExtension
{
/// <summary>
/// A command whose sole purpose is to
/// relay its functionality to other
/// objects by invoking delegates. The
/// default return value for the CanExecute
/// method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
return _canExecute == null ? true : _canExecute(parameters);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameters)
{
_execute(parameters);
}
#endregion // ICommand Members
}
public class RelayCommand<T> : ICommand
{
#region Fields
private readonly Action<T> _execute = null;
private readonly Predicate<T> _canExecute = null;
#endregion
#region Constructors
/// <summary>
/// Creates a new command that can always execute.
/// </summary>
/// <param name="execute">The execution logic.</param>
public RelayCommand(Action<T> execute)
: this(execute, null)
{
}
/// <summary>
/// Creates a new command with conditional execution.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution status logic.</param>
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion
#region ICommand Members
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute((T)parameter);
}
public event EventHandler CanExecuteChanged
{
add
{
if (_canExecute != null)
CommandManager.RequerySuggested += value;
}
remove
{
if (_canExecute != null)
CommandManager.RequerySuggested -= value;
}
}
public void Execute(object parameter)
{
_execute((T)parameter);
}
#endregion
}
}
そして、このBindableBaseクラス:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace Sym.VisualStudioExtension
{
public class BindableBase : INotifyPropertyChanged
{
protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName] string propertyName = null)
{
if (object.Equals(member, val)) return;
member = val;
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
そして、ここではViewModelLocatorです:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using Microsoft.Practices.Unity;
using Symplexity.VisualStudioExtension.Engines;
namespace Sym.VisualStudioExtension
{
public static class ViewModelLocator
{
public static bool GetAutoWireViewModel(DependencyObject obj)
{
return (bool)obj.GetValue(AutoWireViewModelProperty);
}
public static void SetAutoWireViewModel(DependencyObject obj, bool value)
{
obj.SetValue(AutoWireViewModelProperty, value);
}
// Using a DependencyProperty as the backing store for AutoWireViewModel. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AutoWireViewModelProperty =
DependencyProperty.RegisterAttached("AutoWireViewModel", typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false, AutoWireViewModelChanged));
private static void AutoWireViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (DesignerProperties.GetIsInDesignMode(d)) return;
var viewType = d.GetType();
var viewTypeName = viewType.FullName;
var viewModelTypeName = viewTypeName + "Model";
var viewModelType = Type.GetType(viewModelTypeName);
if (viewModelTypeName.Contains("UtilitiesViewModel"))
{
UtilitiesViewModel uViewModel = ContainerHelper.Container.Resolve<UtilitiesViewModel>();
((FrameworkElement)d).DataContext = uViewModel;
}
else
{
var viewModel = ContainerHelper.Container.Resolve(viewModelType);
((FrameworkElement)d).DataContext = viewModel;
}
}
}
}
私はかなりの数を見てきましたリストボックスの項目やマウスのイベントなどについての他のスレッド。そんなに私は混乱してしまったどの経路に行くか。
私は背後にあるコードで何かを持つことはそれほど悪くないです、そしてそれは私がWPFとMVVMについて知っていた少し忘れている私のような誰かのために非常に簡単に見えると思いますが、 RelayCommand、BindableBase、ViewModelLocatorは既に用意されているので、マウスイベント(ダブルクリックと右クリック)をコマンドと接続するように設計されているように感じられますが、どういうわけかはわかりません。 したがって、VSEエディタでListBox(ダブルクリックされている場合)の項目に名前が表示される、基本ファイルを開くTAEngineViewModelのOpenFileメソッドがあるとしたら、XAMLには何を入れますか? 選択したCalcFile/ParameterFileオブジェクトをTAEngineViewModelに渡すにはどうすればよいですか?
私は、右クリックイベントがダブルクリックと似ていると仮定します。そうでない場合はどうなりますか?
ここで見ることができますhttp://stackoverflow.com/questions/11172443/how-to-fire-a-command-on-double-click-listbox-item-using-mvvm –