0

在我的视图模型中,我有一些数学函数,如加法、减法。在我的用户界面中,我有两个文本框,其中包含一个输入,然后是一个组合框。该组合框将包含所有数学函数的名称(加、减)。在确定按钮上,我希望执行选定的功能。我怎么能做到这一点。我的意思是如何在组合框中显示函数名称列表?我可以在那里显示字符串,但函数名称如何。并选择功能。

<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 属性返回一个委托列表。使用预定义的 Func,这是一个不带参数并返回 int 的方法:

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”和 lambda,它只返回具有我们自定义属性的方法。
  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. ComboBox_SelectionChanged 应该通过 ICommand 完成。参考: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 回答