I am trying to master working with the MEF framework by implementing my own version of the well known Calculator example. The user interface is in WPF.
After composition the Viewmodel holds an ObservableCollection(Of IOperation)
that is represented by a 'ListBox' of Buttons
in the View. The text on each Button
is a Char
defined in IOperation
as a property named Symbol
. By binding the ListBox's SelectedItem to a property in the ViewModel I can just fire the Calculate
method of the currently selected IOperation
without knowing which Button
was pressed. (Code illustrating this below.)
However, now I need to add InputBindings
to the View , where each KeyBinding
will be associated with the Symbol
that is defined on the IOperation
. It looks like that I cannot avoid implementing a Select Case
(switch
) statement to iterate through the Viewmodel's collection of IOperation
s to select the one on which the 'Calculate` method should be called.
Any ideas?
THE XAML:
<ListBox Grid.Column="1" Grid.Row="3" Name="OperationsList"
SelectedItem="{Binding ActiveOperation,Mode=TwoWay}"
ItemsSource="{Binding Operations}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Button Content="{Binding Symbol}"
ToolTip="{Binding Description}"
Command="{Binding ElementName=OperationsList, Path=DataContext.ActivateOperation}"
Click="Button_Click_1"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
IOPERATION:
Public Interface IOperation
Function Calculate() As Double
Property Left As Double
Property Right As Double
Property Symbol As String
Property Description As String
End Interface
VIEWMODEL:
Private _activateOperation As Command
Public Property ActivateOperation As Command
Get
Return _activateOperation
End Get
Set(value As Command)
_activateOperation = value
OnPropertyChanged()
End Set
End Property
Public Property ActiveOperation As IOperation
Get
Return _compositor.ActiveOperation
End Get
Set(value As ICalculator)
_compositor.ActiveOperation = value
OnPropertyChanged()
End Set
End Property
Public ReadOnly Property Operations As ObservableCollection(Of IOperation)
Get
Return New ObservableCollection(Of ICalculator)(_compositor.Operations)
End Get
End Property
Private Sub DoActivateOperation(Optional parameter As Object = Nothing)
If Left.HasValue Then
MakeCalculation()
Else
Left = CDbl(Display)
ClearDisplay()
End If
End Sub
Code is a wee rough about the edges so adjust accordingly...
// in ViewModel, after composition
// map string symbols to input Keys (for brevity, using a Dictionary)
Dictionary<string, System.Windows.Input.Key> SymbolsToKeys = new Dictionary<string, Key>
{
{ "+", Key.Add },
// etc.
}
// compose the list (expose it via a public property)
// (ensure not to get confused: the KeyValuePair.Key is for the string symbol
// ... and the KeyValuePair.Value is for the Sys.Win.Input.Key value)
KeyBindings = (from symbolAndKey in SymbolsToKeys
join op in Operations on Equals(symbolAndKey.Key, op.Symbol)
select new KeyBinding(
new Command(op.Calculate)),
new KeyGesture(symbolAndKey.Value)
).ToList();
// in View, after Binding to ViewModel
var vm = DataContext as YourViewModel;
if(vm != null)
{
foreach(var keybinding in vm.KeyBindings){
this.InputBindings.Add(keybinding);
}
}