Экспорт MEF

39

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

Пример хоста для MEF
<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();
        }
    }
}
Пройди тесты
Лучший чат для C# программистов