Экспорт MEF
39C# и .NET --- Основы .NET --- Экспорт MEF
В предыдущем примере вы видели часть Simple Calculator, которая экспортирует тип Calculator со всеми его методами и свойствами. Следующий пример также содержит SimpleCalculator с той же реализацией, которая была показана ранее. Здесь также используется и другая часть — библиотека пользовательских элементов управления WPF (WPF User Control Library) по имени TemperatureConversion, в которой определен пользовательский интерфейс:

<UserControl x:Class="MEF.TemperatureConversion"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ComboBox x:Name="comboFrom" Grid.Row="0" Grid.Column="0" Margin="5" ItemsSource="{Binding}" SelectedIndex="0" VerticalAlignment="Center" />
<ComboBox x:Name="comboTo" Grid.Row="1" Grid.Column="0" Margin="5" ItemsSource="{Binding}" SelectedIndex="0" VerticalAlignment="Center" />
<TextBox x:Name="textInput" Grid.Row="0" Grid.Column="1" Margin="5" VerticalAlignment="Center" />
<TextBox x:Name="textOutput" Grid.Row="1" Grid.Column="1" Margin="5" VerticalAlignment="Center" IsReadOnly="True" />
<Button Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5" VerticalAlignment="Center" Content="Calculate" Click="OnCalculate" />
</Grid>
</UserControl>
Этот элемент обеспечивает преобразования между шкалами Цельсия, Фаренгейта и Кельвина. В первом и втором раскрывающемся списке выбирается исходная и целевая шкала для преобразования. Кнопка Caclculate (Вычислить) запускает вычисление для преобразования значения температуры из одной шкалы в другую.
Пользовательский элемент управления имеет простую реализацию преобразования температур. Перечисление TempConversionType определяет различные преобразования, которые может выполнять данный элемент управления.
Значения перечисления отображаются в двух раскрывающихся списках за счет установки свойства DataContext пользовательского элемента управления в конструкторе.
Метод ToCelsiusFrom() преобразует аргумент t из его исходного значения в значение по Цельсию. Исходный тип температуры определяется вторым аргументом TempConversionType. Метод FromCelsiusTo() преобразует значение по Цельсию в выбранную шкалу температур. Метод OnCalculate() — это обработчик события Button.Click, вызывающий методы ToCelsiusFrom() и FromCelsiusTo() для выполнения преобразования согласно выбранному пользователем типу преобразования:
using System;
using System.Windows;
using System.Windows.Controls;
namespace MEF
{
public enum TempConversionType
{
Celsius,
Fahrenheit,
Kelvin
}
public partial class TemperatureConversion : UserControl
{
public TemperatureConversion()
{
InitializeComponent();
this.DataContext = Enum.GetNames(typeof(TempConversionType));
}
private double ToCelsiusFrom(double t, TempConversionType conv)
{
switch (conv)
{
case TempConversionType.Celsius:
return t;
case TempConversionType.Fahrenheit:
return (t - 32) / 1.8;
case TempConversionType.Kelvin:
return (t - 273.15);
default:
throw new ArgumentException("invalid enumeration value");
}
}
private double FromCelsiusTo(double t, TempConversionType conv)
{
switch (conv)
{
case TempConversionType.Celsius:
return t;
case TempConversionType.Fahrenheit:
return (t * 1.8) + 32;
case TempConversionType.Kelvin:
return t + 273.15;
default:
throw new ArgumentException("invalid enumeration value");
}
}
private void OnCalculate(object sender, System.Windows.RoutedEventArgs e)
{
try
{
TempConversionType from;
TempConversionType to;
if (Enum.TryParse<TempConversionType>((string)comboFrom.SelectedValue, out from) &&
Enum.TryParse<TempConversionType>((string)comboTo.SelectedValue, out to))
{
double result = FromCelsiusTo(ToCelsiusFrom(double.Parse(textInput.Text), from), to);
textOutput.Text = result.ToString();
}
}
catch (FormatException ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
До сих пор этот элемент управления был простым пользовательским элементом WPF. Чтобы создать часть MEF, с помощью атрибута Export осуществляется экспорт класса TemperatureCalculatorExtension. Этот класс реализует интерфейс ICalculatorExtension, предоставляющий информацию Title и Description и возвращающий элемент TemperatureConversion типа UserControl из метода GetUI():
using System.ComponentModel.Composition;
using System.Windows;
namespace MEF
{
[Export(typeof(ICalculatorExtension))]
public class TemperatureCalculatorExtension : ICalculatorExtension
{
public string Title
{
get { return "Преобразование температуры"; }
}
public string Description
{
get { return "Преобразуем C -> F и F -> C"; }
}
public FrameworkElement GetUI()
{
return new TemperatureConversion();
}
}
}
Другим пользовательским элементом управления, который реализует интерфейс ICalculatorExtension, является FuelEconomy. С его помощью можно вычислять количество миль на галлон бензина или расход в литрах бензина на 100 километров:
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace MEF
{
public partial class FuelEconomyUC : UserControl
{
private List<FuelEconomyType> fuelEcoTypes;
public FuelEconomyUC()
{
InitializeComponent();
InitializeFuelEcoTypes();
}
private void InitializeFuelEcoTypes()
{
var t1 = new FuelEconomyType
{
Id = "lpk",
Text = "L/100 km",
DistanceText = "Distance (kilometers)",
FuelText = "Fuel used (liters)"
};
var t2 = new FuelEconomyType
{
Id = "mpg",
Text = "Miles per gallon",
DistanceText = "Distance (miles)",
FuelText = "Fuel used (gallons)"
};
fuelEcoTypes = new List<FuelEconomyType>() { t1, t2 };
this.DataContext = fuelEcoTypes;
}
private void OnCalculate(object sender, RoutedEventArgs e)
{
double fuel = double.Parse(textFuel.Text);
double distance = double.Parse(textDistance.Text);
FuelEconomyType ecoType = comboFuelEco.SelectedItem as FuelEconomyType;
double result = 0;
switch (ecoType.Id)
{
case "lpk":
result = fuel / (distance / 100);
break;
case "mpg":
result = distance / fuel;
break;
default:
break;
}
this.textResult.Text = result.ToString();
}
}
}
Интерфейс ICalculatorExtension определен и экспортирован с помощью атрибута Export:
using System.ComponentModel.Composition;
using System.Windows;
namespace MEF
{
[Export(typeof(ICalculatorExtension))]
public class FuelCalculatorExtension : ICalculatorExtension
{
public string Title
{
get { return "Fuel Economy"; }
}
public string Description
{
get { return "Calculate fuel economy"; }
}
public FrameworkElement GetUI()
{
return new FuelEconomyUC();
}
}
}