Jaa


Как разделять код между .Net и Silverlight-проектами. Часть 1

imageСпособ #1. Разделять собственно код (исходники)

Представьте себе, что у нас есть два проекта, к примеру, Silverlight-проект и .Net-проект, которые отчасти дублируют функциональность, по существу, должны использовать одинаковый код (например, при описании отдельных контролов или бизнес-логики).

Естественно, в такой ситуации хочется

  • писать код единожды,
  • хранить его в одном месте,
  • использовать в обоих проектах.

Как это сделать?

 

Для примера создадим какой-нибудь простой класс с бизнес-логикой.

Конечно, при этом нужно помнить, что Silverlight-версия .Net отличается от полной и, таким образом, выступает как ограничивающий фактор — разделяемый код не может содержать что-то, что не поддерживает Silverlight.

Чтобы сделать разделяемый код более видимым (и заметным, что он именно разделяемый — единообразно для обоих проектов), сделаем отдельную папку (Add → New Solution Folder).

Итак, добавим новый класс Person, в котором будет только несколько полей, касающихся имени человека.

image

Содержание класса будет следующим:

 public class Person
{
    private String m_firstName;
    private String m_lastName;

    public Person()
    {
    }
    
    private String UpperCaseFirstLetter(String str)
    {
        if (String.IsNullOrEmpty(str) || str.Length == 0)
            return str;

        return str[0].ToString().ToUpper() + str.Substring(1, str.Length - 1);
    }

    public String FirstName
    {
        get { return m_firstName; }
        set { m_firstName = UpperCaseFirstLetter(value); }
    }

    public String LastName
    {
        get { return m_lastName; }
        set { m_lastName = UpperCaseFirstLetter(value); }
    }

    public String FullName
    {
        get { return String.Format("{0} {1}", FirstName, LastName); }
    } 
}

 

Следующий шаг: добавить ссылку на этот файл в оба проекта. Для этого для каждого из проектов (Silverlight и WPF) проделываем следующую операцию: Add → Existing Item…, выбираем наш файл и вместо Add выбираем Add as Link:

image

После этого мы будем иметь ссылку на этот класс в обоих проектах!

image

 

Теперь проверим, как этот код будет использоваться в наших проектах.

 

Добавим немного кода в CodeSharingSL → Page.xaml (для использования WrapPanel нужно добавить в References ссылку на библиотеку Microsoft.Windows.Controls.dll из Silverlight Toolkit):

 <UserControl x:Class="CodeSharingSL.Page"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"
    Width="400" Height="300">
    <Border x:Name="LayoutRoot" Background="White" Margin="20" HorizontalAlignment="Left" CornerRadius="5" BorderBrush="LightGray" BorderThickness="1" >
        <controls:WrapPanel Width="225" Margin="20" >
            <TextBlock Width="75" Text="First Name:" />
            <TextBox Width="150" Text="{Binding FirstName, Mode=TwoWay}" TabIndex="1" />
            <TextBlock Width="75" Text="Last Name:" />
            <TextBox Width="150" Text="{Binding LastName, Mode=TwoWay}" TabIndex="2" />
            <TextBlock Width="75" Text="Full Name:" />
            <TextBox Width="150" x:Name="txtFullName" IsReadOnly="True" InputMethod.IsInputMethodEnabled="False" />
            <Button Content="Update full name" Margin="0 10 0 0" Click="Button_Click" />
        </controls:WrapPanel>
    </Border>
</UserControl>

И изменим соответствующим образом Page.xaml.cs, добавив обработчики событий и привязкук тому самому классу Person:

 using SharedCode;

namespace CodeSharingSL
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();

            this.Loaded += new RoutedEventHandler(Page_Loaded);
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            this.DataContext = new Person();
        }

        private void Button_Click(Object sender, RoutedEventArgs e)
        {
            txtFullName.Text = ((Person)this.DataContext).FullName;
        }
    }
}

Компилируем, смотрим результат:

image

Работает!

 

Поехали дальше. Правим WPF-проект, начнем с xaml-файла CodeSharingWPF →Window1.xaml, в целом все будет аналогично, но не идентично :)

 <Window x:Class="CodeSharingWPF.Window1"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Grid Background="Black">
        <WrapPanel Width="225" Margin="20" Background="Black"  >
            <TextBlock Width="75" Text="First Name:" Foreground="White"/>
            <TextBox Width="150" Text="{Binding FirstName}" TabIndex="1" />
            <TextBlock Width="75" Text="Last Name:" Foreground="White"/>
            <TextBox Width="150" Text="{Binding LastName}" TabIndex="2" />
            <TextBlock Width="75" Text="Full Name:" Foreground="White"/>
            <TextBox Width="150" x:Name="txtFullName" IsReadOnly="True" InputMethod.IsInputMethodEnabled="False" />
            <Button Content="Update Full Name" Margin="0 10" Click="Button_Click" />
        </WrapPanel>
    </Grid>
</Window>

C#-код будет практически таким же:

 using SharedCode;

namespace CodeSharingWPF
{    
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            this.Loaded +=new RoutedEventHandler(Window1_Loaded);
        }

        void  Window1_Loaded(object sender, RoutedEventArgs e)
        {
             this.DataContext = new Person();
        }

        private void Button_Click(Object sender, RoutedEventArgs e)
        {
            txtFullName.Text = ((Person)this.DataContext).FullName;
        }
    }
}

 

Запускаем, смотрим результат:

image

Вуаля :) Впереди еще две части: про использование условной компиляции применительно к проблеме разделения кода и про то, как разделять не код, а библиотеки (dll).

 Исходники прилагаются.

Comments

  • Anonymous
    February 08, 2009
    Способ #1. Разделять собственно код (исходники)

  • Anonymous
    February 08, 2009
    В прошлый раз мы разобрались, как разделять код между Silverlight и .NET-проектами на уровне исходников

  • Anonymous
    February 08, 2009
    Итак, мы уже умеем делать две вещи: Разделять код между .NET и Silverlight-проектами на уровне исходников

  • Anonymous
    February 08, 2009
    В прошлый раз мы разобрались, как разделять код между Silverlight и .NET-проектами на уровне исходников