C#代码到处致力于便携式类库

如今,如果您可以使用C#编写代码,您可以编写Windows,Linux和OSX的代码,您的代码可以在桌面,服务器,移动或嵌入式设备上运行。所以C#几乎无处不在,如果你是C#开发者是一件好事!  微笑 只有很少的打嗝,即使c#是标准化语言,也有多个运行时现有的c#运行。这可能导致假设必须为每个运行时重写代码。由于标准.NET C#库无法在Silverlight运行时重用或新的Windows RT运行时重复使用,或者我认为您收到消息。但恐惧不 - 感谢便携式类库(PCL),可以编写可以在多个平台上重复使用的代码。

便携式库

添加便携式类库(PCL)时,您必须选择要使用该平台的哪些平台。支持的平台对PCL提供的功能影响,而无需添加任何其他库(通常通过Nuget)。您可以找到每个平台支持的库列表 MSDN. .

对于此帖,我们将希望在以下平台上重用我们的代码:

  • 通用Windows应用程序(Windows 10)
  • Classic Desktop WPF应用程序
  • ios(与Xamarin)
  • Android(与Xamarin)

为了保持简单,应用程序中的逻辑将创建一个人的列表。我们甚至可以从PCL分享我们的视图模型,因此我们将在创建应用程序时唯一的开销是实际的UI代码,并将视图模型接线到实际视图。现在在这个设置中,令人惊叹的时间似乎是边缘的,但​​考虑你的标准商业应用程序,节省的节省将开始以主要方式快速加起来。

创建PCL.

添加平台特定项目非常直接。只需在添加新项目时将相应的项目模板添加到解决方案中,因此我会留下它,然后转到添加PCL。添加PCL时,将打开一个对话框,以选择应支持的平台即,可以消耗PCL。

显示添加可移植类库Visual Studio对话框,使用.NET Framework 4.6,Windows Universal 10.0,Xamarin.Android和Xamarin.iOS选择

安装Xamarin工具链后,IOS和Android选项将显示。

使用的平台,我们现在可以开始实现我们的案例中的“业务逻辑”是我们调用的简单发电机 personservice.cs. :

public class PersonService
{
    public async Task<IEnumerable<Person>> GetPeople(int count = 42)
    {
        var people = new List<Person>(count);
        // In case of large counts lets be safe and not run this on the UI thread
        await Task.Run(() =>
        {
            for (int i = 0; i < count; ++i)
            {
                people.Add(new Person{FirstName = NameGenerator.GenRandomFirstName(), LastName = NameGenerator.GenRandomLastName()});
            }
        });

        return people;
    }
}

要将我们的数据呈现给UI,我们将使用MVVM模式。

添加MVVM光

在项目中使用MVVM时(始终为我)  眨眼微笑 )我更喜欢使用MVVM光。通过简单安装a可以添加MVVM光 尼古特 package:

PM> Install-Package MvvmLightLibs

由于我们将访问平台的视图模型,请务必将MVVM灯库添加到特定于平台的代码基础。

现在我们可以添加视图模型 MainViewModel.cs. 这将举办我们将显示的人员列表。

public class MainViewModel:ViewModelBase
{
    private readonly IPersonService _personService;

    public MainViewModel(IPersonService personService)
    {
        if (personService == null) throw new ArgumentNullException(nameof(personService));
        _personService = personService;
        if (IsInDesignMode)
        {
            People = new ObservableCollection<Person> {new Person{FirstName = "Doctor Who"}, new Person {FirstName = "Rose", LastName = "Tyler"}, new Person {FirstName = "River", LastName = "Song"} };
        }
        else
        {
            People = new ObservableCollection<Person>();
        }
    }

    public ObservableCollection<Person> People { get; set; }

    public async Task InitAsync()
    {
        var people = await _personService.GetPeople();
        People.Clear();
        foreach (var person in people)
        {
            People.Add(person);
        }
    }
}

接下来我们仍然需要配置 ViewModellocator.cs. ,这允许我们轻松管理依赖项。

public class ViewModelLocator
{
    public ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        SimpleIoc.Default.Register<IPersonService, PersonService>();
        SimpleIoc.Default.Register<MainViewModel>();
    }

    public MainViewModel MainViewModel => SimpleIoc.Default.GetInstance<MainViewModel>();
}

所以现在我们拥有我们所有的跨平台代码设置。让我们在我们想要的目标上运行它。

平台

在平台上,我们可以简单地引用PCL,如我们可能使用和访问功能的任何其他库。在我们的平台上,我们必须执行以下步骤:

  1. 创建UI.
  2. 挂钩 ViewModellocator.cs.
  3. 将视图模型连接到视图

让我们为通用Windows应用程序执行这些步骤。

通用Windows应用程序(UWA)

为了查看我们将简单地添加一个 列表显示 到了 mainPage.xaml. :

<Page
    x:Class="PclSample.UWA.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclSample.UWA"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="..."
    mc:Ignorable="d">

    <ListView ItemsSource="{Binding People}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding FirstName}"/>
                <TextBlock Text="{Binding LastName}"/>
                </StackPanel>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

在Windows下(对于WPF也是如此)MVVM灯真的很好地集成了。我们可以简单地添加到的定位器 app.xaml. :

<Application
    x:Class="PclSample.UWA.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclSample.UWA"
    RequestedTheme="Light">
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" xmlns:vm="using:PclSample.Core" />
        <ResourceDictionary />
    </Application.Resources>
</Application>

这允许我们访问属性 ViewModellocator.cs. 我们查看的课程I.. mainPage.xaml. 。所以下一步将把视图模型接线到视图 datacontext. ,这将填充视图:

<Page
    x:Class="PclSample.UWA.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:PclSample.UWA"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    DataContext="{Binding Source={StaticResource Locator}, Path=MainViewModel}"
    mc:Ignorable="d">

    ...
</Page>

现在所有人都设定了,我们可以享受我们轻微的uwa的看法。

在Windows 10移动模拟器中运行的UWA屏幕截图

Windows演示基础(WPF)

遵循与WPF应用程序中的UWA中相同的步骤将导致相同的结果。

显示以WPF桌面应用程序运行的示例应用程序

因此,我们可以将所有业务逻辑从一个Microsoft客户端开发模型重用到另一个Microsoft客户端开发模型。这不是很棒吗?  微笑 但等等有更多。我们可以在Microsoft Ecosystem之外的C#代码。与例如Xamarin一起,我们可以在iOS和Android上重用我们的C#代码。

iOS.

在iOS下,UI通常在设计器中创建(类似于Windows窗体),因此无法显示很多代码。我们补充说 列表显示 与ios a相同 UITATYVIEW. 到一个页面并给它一个名字,在这个样本中 Peoplableview. .

显示iOS设计器以及设置UITableView的名称。

建立 ViewModellocator.cs. 当我们离开Microsoft平台但后来,它并不像优雅,那么它就可以轻松完成。在里面 appdelegate.cs. 这是每个iOS应用程序的启动点我们只需创建一个实例 ViewModellocator.cs. 并将其存放在房产中。然后可以在整个IOS应用程序中访问该属性。查看模型的接线是在的 ViewController.cs. 这与我们之前设置的视图相关联:

public partial class ViewController : UIViewController
{
    ObservableTableViewController<Person> _tableViewController;

    public ViewController (IntPtr handle) : base (handle)
    {
    }

    private MainViewModel Vm => Application.Locator.MainViewModel;

    public override void ViewDidLoad ()
    {
        base.ViewDidLoad ();
        // Perform any additional setup after loading the view, typically from a nib.

        _tableViewController = Vm.People.GetController(CreatePersonCell, BindPersonCell);
        _tableViewController.TableView = PeopleTableView;
    }

    public override async void ViewWillAppear (bool animated)
    {
        base.ViewWillAppear (animated);
        await Vm.InitAsync();
    }

    public override void DidReceiveMemoryWarning ()
    {
        base.DidReceiveMemoryWarning ();
        // Release any cached data, images, etc that aren't in use.
    }

    UITableViewCell CreatePersonCell (Foundation.NSString reuseId)
    {
        var cell = new UITableViewCell(UITableViewCellStyle.Default, null);
        return cell;
    }

    void BindPersonCell (UITableViewCell cell, Person person, Foundation.NSIndexPath path)
    {
        cell.TextLabel.Text = person.FullName;
    }
}

现在所有这些都是为我们做的事情再次启动iOS模拟器来验证一切是否正确,我们拥有它,我们用于我们的WPF和UWA应用程序的相同C#代码现在正在IOS下运行:

 苹果手机

安卓

我们在iOS下做了什么,我们也可以在Android下复制。虽然没有Microsoft Eco系统的一部分,但如果您已经写了WPF,现代应用程序(以及他们拥有的所有其他花哨的名称,则该模型应该更熟悉。在资源/布局下有 main.axml. 这是一个(应用程序)XML文件,我们可以编辑以告诉Android操作系统如何呈现UI。听起来像XAML吧?并且概念也在某些部分中重叠。添加A. 列表显示 到XML并设置允许我们稍后访问它的元素的ID:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">
    <ListView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/PeopleListView" />
</LinearLayout>

我们再次必须设置定位器。在Android下没有固定的设置点,所以我们将使用静态类 locator.cs. 我们将从Android应用程序访问的财产:

internal static class Locator
{
    private static readonly Lazy<ViewModelLocator> _locator = new Lazy<ViewModelLocator>(() => new ViewModelLocator());
    public static ViewModelLocator Instance => _locator.Value;
}

接线查看模型 MainActivity.cs. ,您可以将其视为作为代码/ ViewController等效的代码。我在这里的前博客文章中更详细地写了关于这种绑定的绑定。

[Activity(Label = "PclSample.Droid", MainLauncher = true, Icon = "@drawable/icon")]
internal class MainActivity : Activity
{
    protected override async void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        // Set our view from the "main" layout resource
        SetContentView(Resource.Layout.Main);

        await Vm.InitAsync();

        // Get our button from the layout resource,
        // and attach an event to it
        PeopleListView.Adapter = Vm.People.GetAdapter(GetPersonView);
    }

    public ListView PeopleListView => FindViewById<ListView>(Resource.Id.PeopleListView);

    private MainViewModel Vm => Locator.Instance.MainViewModel;

    private View GetPersonView(int position, Person person, View convertView)
    {
        View view = convertView ?? LayoutInflater.Inflate(Android.Resource.Layout.SimpleListItem1, null);

        view.FindViewById<TextView>(Android.Resource.Id.Text1).Text = person.FullName;

        return view;
    }
}

请注意,我们之前设置的ID允许我们检索UI控件。

此时我们可以启动Android仿真器,只是提到它Visual Studio 2015提供了一个伟大的Android仿真器 - 股票仿真器的方式更好!我们可以再次看到该应用程序正在运行重用我们藏在我们的PCL中的C#代码。

显示在Android仿真器中运行的应用程序

结论

在此博客文章中,我们看到如何使用便携式类库(PCL)共享C#代码。 PCL可以包含在所有主要的C#堆栈.NET中,UWP,Silverlight,XAmarin等。虽然PCL中的功能更具限制,但它确实允许从传统的WPF / Win表单应用中共享代码到移动应用程序。

通过安装更多的核保存,如存储,网络访问等,可以扩展PCL。 PCL现在已经存在了几年,并在编写跨平台应用程序时被证明是一个有价值的组成部分。

整个样本都可以找到 GitHub. .

Updated: