2013-02-25 3 views
0

В моей модели модели у меня есть некоторые математические функции, такие как добавление, вычитание. В моем пользовательском интерфейсе у меня есть два текстовых поля, которые будут содержать вход, а затем есть выпадающий список. Это поле со списком будет содержать имя всех математических функций (add, subtract). И на кнопке 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; 
} 
+0

Вы хотите добавить функции в файле 'ComboBox' или имена функций? то есть. 'string's. – Guillaume

+0

На самом деле имена функций. В этом случае поле со списком будет содержать AddFunction, SubtractFunction. –

+0

Простыми словами это должно быть так, что я выбираю функцию из поля со списком и затем ОК. В OK нажмите, я не проверяю, что такое значение поля combox. Я просто делаю, что selectedAction.Exceute (или что-то вроде этого). Я не хочу, если else проверяет, что, если строка boxox добавляется, тогда выполните это, сделайте это. –

ответ

1

Ниже пример, который может помочь:

TODO: 1. Результат должен к переплетены другому TextBlock в UI 2. ComboBox_SelectionChanged должно быть сделано с помощью ICommand. Ref: 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; 
    } 
} 
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; 
    } 
} 

Далее следует использовать преобразователь. Как правило, конвертер является частью «View», поэтому поместите его в код, расположенный за файлом 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. Теперь в действиях используется отражение. Обратите внимание на «Где» и лямбда для предиката фильтра, который возвращает только те методы, которые имеют наш пользовательский атрибут.
  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; 
     } 

    } 
} 
Смежные вопросы