0

私のビューモデルには、加算、減算などの数学関数があります。私のユーザーインターフェイスには、入力を含む2つのテキストボックスがあり、次にコンボボックスがあります。このコンボボックスには、すべての数学関数(加算、減算)の名前が含まれます。そして、OKボタンで選択した機能を実行したい。どうすればこれができますか。コンボボックスに関数名のリストを表示するにはどうすればよいですか?そこに文字列を表示することはできますが、関数はどのように名前を付けますか。そして、選択された機能も。

<ComboBox ItemsSource="{Binding Actions}" SelectedItem="{Binding SelectedAction}" />

モデルを表示

public IEnumerable<string> Actions
{
    get
    {
        var list = new List<string>();
        list.Add("Add");      // Instead of adding strings, I want to add functions.
        list.Add("Subtract"); 
        return list;
    }
}

public int AddFunction()
{
    return numberA + numberB;
}

public int SubtractFunction()
{
    return numberA - numberB;
}
4

2 に答える 2

1

したがって、デリゲートのリストと、デリゲートをメソッド名に変換するコンバーターが必要です。

ViewModel で、Actions プロパティがデリゲートのリストを返すようにします。引数を取らず、int を返すメソッドである定義済みの Func を使用します。

public IEnumerable<Func<int>> Actions
{
    get
    {
        List<Func<int>> list = new List<Func<int>>();
        list.Add( AddFunction );
        list.Add( SubstractFunction );
        return list;
    }
}

次に、コンバーターを実装します。通常、コンバーターは「ビュー」の一部であるため、分離コード cs ファイルに配置します。この変換Func<int>は文字列に変換し、リフレクションを使用してそれを行います。

[ValueConversion( typeof( Func<int> ), typeof( string ) )]
public class FnConverter : IValueConverter
{
    public object Convert( object value, Type targetType, object parameter, CultureInfo culture )
    {
        Func<int> fn = value as Func<int>;
        return fn.Method.Name;
    }

    public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture )
    {
        return null;
    }
}

最後に、XAML でコンバーターを使用する必要があります。ただし、そのためには、コンバーターが適用されるコンボ ボックスのアイテム テンプレートを指定する必要があります。

<!-- earlier in code define the converter as a resource -->
<Window.Resources>
    <src:FnConverter x:Key="conv" />
</Window.Resources>

...

<!-- now the combo box -->
<ComboBox Margin="4" ItemsSource="{Binding Path=Actions}">
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=., Converter={StaticResource conv}}"  />
        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

そうは言っても、さらに洗練された解決策は、ビューモデルに MethodInfo のリストを保持することだと思います。カスタム属性を使用してこのリストを生成します。いくつかのコードの下。次の点に注意してください。

  1. PresentingAttribute はカスタム属性です。System.Reflection.Attribute から派生します。何もありません。必要に応じて、「ラベル」、「説明」などのパラメーターを追加できます。
  2. コンボボックスに入れたいメソッドを「Presenting」でデコレーション
  3. 現在、Actions はリフレクションを使用しています。カスタム属性を持つメソッドのみを返すフィルター述語の「Where」とラムダに注意してください。
  4. MethodInfo を受け取るようにコンバーターを変更する必要があります。
namespace SO
{
    class PresentingAttribute : Attribute
    {
    }

    class FnVM
    {
        public int numA { get; set; }
        public int numB { get; set; }

        public IEnumerable<MethodInfo> Actions
        {
            get
            {
                return typeof( FnVM ).GetMethods().Where( minfo => 
                    minfo.GetCustomAttribute( typeof( PresentingAttribute ) ) != null
                );
            }
        }


        [Presenting]
        public int AddFunction( )
        {
            return numA + numB;
        }

        [Presenting]
        public int MulFunction( )
        {
            return numA * numB;
        }

    }
}
于 2013-02-25T21:35:49.650 に答える
1

役立つ例を以下に示します。

TODO: 1. 結果は UI の別のテキストブロックにバインドする必要があります。 2. ICommand を介して ComboBox_SelectionChanged を実行する必要があります。参照: mvvm-binding-treeview-item-changed-to-icommand

    public IList<MyComboboxItem> Actions
    {
        get
        {
            var list = new List<MyComboboxItem> { new MyComboboxItem(AddFunction), new MyComboboxItem(SubtractFunction) };
            return list;
        }
    }

    public int numberA { get;  set; }
    public int numberB { get; set; }

    public int Result { get; private set; }

    public void AddFunction()
    {
        Result = numberA + numberB;
    }

    public void SubtractFunction()
    {
        Result = numberA - numberB;
    }

    private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var comboboxItem = e.AddedItems[0] as MyComboboxItem;
        if (comboboxItem != null)
            comboboxItem.Action.Invoke();
    }

    public event PropertyChangedEventHandler PropertyChanged;




  public class MyComboboxItem 
  {
    public Action Action { get; private set; } 

    public MyComboboxItem(Action action)
    {
        this.Action = action;
    }

    public override string ToString()
    {
        return Action.Method.Name;
    }
}
于 2013-02-25T09:10:32.823 に答える