当前位置:网站首页 / xamarin / 正文

AY VS2022 xamarin基础-Xamarin.Android入门

时间:2021年06月24日 | 作者 : aaronyang | 分类 : xamarin | 浏览: 7553次 | 评论 0

 Xamarin.Android 是一种 Xamarin 框架,可用于在 Visual Studio 中通过 C# 创建完全原生的 Android 应用

image.png

可以使用 Visual Studio 或 Visual Studio for Mac 来生成 Xamarin.Android 应用。 Xamarin.Android 支持最新的 C# 功能,其中包括泛型、async/await、LINQ 和 Lambda 表达式。 这种支持意味着创建 Android 应用程序时,所有熟悉的 C# 语言构造均可用。


例如,以下代码在编译时不会出现任何问题:

var employees = new List<Employee>();
var seniors = from e in employees where e.Salary > 50000 select e;
var client = new HttpClient();
var result = await client.GetStringAsync("");

作为 Xamarin.Android 开发人员,你也可以访问这些库。

image.png

假设你要访问监视用户心率的蓝牙配件。 此类配件通常附带一个 SDK,你可以在自己的基于 Java 的 Android 应用中使用。



可以将现有的 Java .jar 文件合并到 Xamarin.Android 应用中。 若要合并库,可以使用:

Java 本机接口 (JNI)

Java 绑定库

这两种方法都不简单,但都能完成任务。

选择哪种方法取决于个人偏好。 如果使用 JNI,代码看起来会很冗长,就像使用反射式 API 一样。 绑定库生成更好的客户端代码,但是需要进行更多的准备工作。


image.png

项目类型描述

Android 应用 (Xamarin)使用此标准项目模板创建 Android 应用。 此模板创建可在手机或平板电脑上运行的应用。

Android 穿戴设备应用 (Xamarin)此模板创建适用于可穿戴设备的 Android 应用。 通常是手表样式的应用。

Android 类库 (Xamarin)此模板创建一个仅针对 Xamarin.Android 平台的 C# 类库。 该库只能在 Xamarin.Android 项目之间进行共享。 如果要创建跨平台共享库,请使用 .NET Standard 类库。

Android 绑定库 (Xamarin)使用此模板创建 Android 绑定项目。 通过该项目可创建自己的 C# 包装器,用于绑定你可能想要使用的任何 Java Android 库。


创建一个 TipCalculator 的Xamarin.Android项目

image.png

选择这个创建,点击下一步

image.png

image.png

模板                     描述

单一视图应用程序这是基本的应用程序模板。 将在实验室练习中使用。 它创建包含按钮的单页应用结构。

导航抽屉式应用此模板创建带两个面板的应用程序。 第一个面板为菜单结构,用户可通过其中的各项导航到某个页面。 第二个面板充当所选菜单选项的页面占位符。

选项卡式应用此模板创建多页应用程序,其中每一页都是一个选项卡。表示选项卡的按钮显示在屏幕底部。

空白应用此模板创建一个包含空的视觉对象设计文件和相关代码类的应用程序。


在视图中打开文件 activity_main.xml

image.png

image.png

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:popupTheme="@style/AppTheme.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

    <include layout="@layout/content_main" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>

第一个有趣的项目是 CoordinatorLayout,它是此屏幕的布局容器。 CoordinatorLayout 就像我们已经看过的布局容器一样,但它具有附加功能。 CoordinatorLayout 可以管理其子布局容器之间的交互。

下一个有趣的项目是 AppBarLayout。 此控件用作布局容器,管理应用中显示的应用程序栏。

最后一个有趣的项目是 FloatingActionButton。 此浮动按钮位于内容之上并促进主要操作。 用户可以在应用运行时点击它。

我们不会在本模块中详细介绍这些项目。 Android 有大量文档介绍这些控件。

FloatingActionButton就是界面右下角的那个邮件按钮




MainActivity.cs文件中

MainActivity 的 Activity 属性已将 MainLauncher 设置为 true

代表程序主入口

image.png

设置对应的UI界面 SetContentView(Resource.Layout.activity_main);

FindViewById根据ID获取View的引用,  Toolbar toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);


然后F5,或者单击顶部的运行

image.png


为活动生成 UI

image.png

image.png

写一个 输入 显示多少位的PI的值的文本功能的 程序

    Button 显示用于激活功能的交互式按钮。

    TextView 是一段只读文本。

    EditText 是一个编辑控件,通过该控件可从屏幕键盘或硬件键盘输入数据。

image.png

image.png

像 Button 这样的独立元素继承自 View。 有多个视图的元素派生自 ViewGroup。 这种排列方式增加了子视图(如列表和网格)集合管理功能。 Android 还可以使用派生自 ViewGroup 的面板,将控件组合在一起。 这些视图称为版式面板。

image.png

image.png

image.png


布局文件

例如 TipCalculator\TipCalculator\Resources\layout\activity_main.xml

layout文件夹下的内容


“Resources”文件夹包含几种类型的文件:

drawable:映像文件。

mipmap 各种大小的图标。 文件夹名称指示图像的预期屏幕密度。 Mdpi 表示大约 160 dpi 的中密度屏幕,hdpi 表示大约 240 dpi 的高密度屏幕,依此类推。 可提供多种尺寸的相同图像,Android 会根据设备的屏幕密度自动选择正确的图像。

layout:UI 布局文件。

values: 字符串、颜色、样式等。 “值”文件夹中的文件可让你不必在布局文件中对这些值进行硬编码。 可在此处定义值,然后在各布局文件中查找。

image.png

对象在程序集中定义为类型。 若要从程序集进行实例化,需知道要引用的程序集。 在 XML 中定义 UI 也是间接地使对象实例化。 若要实例化类型,Android 运行时需要 UI XML 包含 Android 名称空间 http://schemas.android.com/apk/res/android。 此命名空间指定了定义常见 Java Android 类型的程序集。 此命名空间由 xmlns: 属性声明:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical">

根据约定,将字符串 android 映射到 Android 命名空间。 使用字符串 android 只是一种约定。 该约定几乎全球通行,因此被视为最佳做法。

包含非常见 Android 类型时,你将定义其他命名空间。 例如,你可能已创建使用自定义属性的自定义控件。



视图通常要求你设置其宽度和高度。 此类视图的一个示例是 LinearLayout。

LinearLayout 需要你在 XML 布局文件中对每个元素设置 layout_width 和 layout_height 属性。 如果不设置这两个属性,会出现运行时异常。

自动调整视图大小

Android 提供了两个可用于 layout_width 和 layout_height 的值。 这两个值具有特殊的行为:

    match_parent:使此元素与其父元素的大小相同。

    wrap_content:使此元素的大小足以容纳其内容。

这两个值的使用频率较高。 将这两个大小调整值与嵌套的版式面板结合使用,就可以生成相当复杂的 UI。

希望由子元素的父级(通常是版式面板)管理子元素的大小时,就会用到自动调整大小。


根据像素设置大小

需要由子元素自行管理自己的大小时,可以使用特定单位设置子元素大小。 Android 允许以像素 (px) 为单位指定大小。

<Button android:layout_width="100px" ... />

但是,Android 的最佳做法指南建议你避免使用 px。


什么是密度无关像素?

<Button android:layout_width="100dp" ... />

目的是无论设备的屏幕密度如何,都让该按钮占据屏幕上大致相同的区域。 在高分辨率屏幕上,该按钮将占用超过 100 个物理像素。

在 500 dpi 和 250 dpi 的两个屏幕上,宽度为 100 dp 的按钮看上去大小差不多。 若要在这两种屏幕中实现所需的大小,它将占用不同数量的物理像素。

Android 最佳做法指南建议使用与密度无关的像素来指定大小。



打开解决方案。

打开 MainActivity.cs。

删除方法 private void FabOnClick(object sender, EventArgs eventArgs)。 这是 FloatingActionButton 的事件处理程序。 练习中不会用到此按钮。

从 MainActivity 中删除 FloatingActionButton 变量。 同时删除其 Click 事件订阅。 完成后,MainActivity 类应与以下代码匹配:


删除

activity_main.xml中的FloatingActionButton 

<com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />


发现activity_main.xml中的 局部视图 代码

    <include

        layout="@layout/content_main" />

打开content_main.xml文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main" android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content" android:text="计算"/>  

</LinearLayout>

image.png

切换到设计,然后打开工具箱,拖4个TextView到计算的下方

image.png

然后拖动布局过去

image.png

自己尝试拖动,最终效果 2个水平linearlayout,每个里面有2个textview

然后选中每行最左边的text view,F4设置 文本属性

image.png

image.png

查看自动生成的代码如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main"
    android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:inputType="text" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="计算"/>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout1" >
        <TextView
            android:text="小费"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/textView1"/>
        <TextView
            android:text="Text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/textView2" />
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout2" >
        <TextView
            android:text="总额"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/textView3" />
        <TextView
            android:text="Text"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/textView4" />
    </LinearLayout>


</LinearLayout>

设计器会自动将 android:id="@+id/..." 添加到已向布局添加的每个控件中

删除 android:id="@+id/..." 属性。 你将在接下来的练习中添加新的 Id 属性。

运行

image.png



现在练习,后台写法,也叫活动 行为

在以下两个文件中定义活动:

    UI 的 XML 布局文件。

    实现行为的 C# 代码文件

在 AndroidManifest.xml 文件中直接指定的任何信息将始终取代代码中提供的任何属性或定义。 换句话说,如果直接在此文件中设置值,这些值将始终优先于编译器提供的任何值。



Resource.designer.cs是根据布局文件自动生成的

image.png

这个文件包含了 很多东西

比如

image.png

Layout这个类,添加一个 活动,活动的名字 在这里就会也有同名的一个常量

image.png

上方还有个Id类,里面存储每个界面用到的id值,通过默认的这两行代码,能看出来

image.png



打开 content_main.xml文件

给控件添加ID

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:showIn="@layout/activity_main"
    android:orientation="vertical">

    <EditText
        android:layout_width="match_parent" android:id="@+id/inputBill"
        android:layout_height="wrap_content"
        android:inputType="text" />
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"    android:id="@+id/calculateButton" 
        android:text="计算"/>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout1" >
        <TextView
            android:text="小费"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" android:layout_marginRight="20dp"
            android:id="@+id/textView1"/>
        <TextView
            android:text=""
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/outputTip" />
    </LinearLayout>
    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/linearLayout2" >
        <TextView
            android:text="总额"
            android:layout_width="wrap_content"
            android:layout_height="match_parent" android:layout_marginRight="20dp"
            android:id="@+id/textView3" />
        <TextView
            android:text=""
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:id="@+id/outputTotal" />
    </LinearLayout>


</LinearLayout>

id要以@+id/  开头

android:layout_marginRight="20dp" 设置右侧的margin


打开MainActivity.cs,找到这些控件

   w.EditText inputBill;
        w.Button calculateButton;
        w.TextView outputTip;
        w.TextView outputTotal;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            SetContentView(Resource.Layout.activity_main);


            inputBill = FindViewById<w.EditText>(Resource.Id.inputBill);
            outputTip = FindViewById<w.TextView>(Resource.Id.outputTip);
            outputTotal = FindViewById<w.TextView>(Resource.Id.outputTotal);
            calculateButton = FindViewById<w.Button>(Resource.Id.calculateButton);


            Toolbar toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);


        }

找到了以后,给按钮添加事件,计算15%的小费

            calculateButton.Click += CalculateButton_Click;

            Toolbar toolbar = FindViewById<Toolbar>(Resource.Id.toolbar);
            SetSupportActionBar(toolbar);


        }

        private void CalculateButton_Click(object sender, EventArgs e)
        {
            string text = inputBill.Text;
            double bill = 0;
            if (double.TryParse(text, out bill))
            {
                var tip = bill * 0.15;
                var total = bill + tip;
                outputTip.Text = tip.ToString();
                outputTotal.Text = total.ToString();
            }
        }

F5运行程序,输入100,点击按钮

image.png


你现在已了解了如何创建基本的 Xamarin.Android 应用。 Xamarin.Android 在后台使用了许多本机 Android 工具和库。 本单元的目标是让你充分了解 Xamarin.Android 如何使用这些工具和库来确保开发环境保持最新。

image.png

如果希望 Xamarin.Android 应用使用 Android 新版本,可以更新开发计算机上安装的基础 Android SDK

我们暂不考虑 Android,先谈一谈 Java。

image.png

Java 应用是使用 Java 开发工具包 (JDK) 中的工具和库生成的。 JDK 包含 Java 应用所需的几项资源:


包含大量实用程序类的标准 Java 库。 这些类用于字符串处理、网络、GUI 生成、数据库访问、文件操作等。 Java 库类似于 .NET Framework 类库。

像 Java 编译器这样的工具。

执行环境。

一些 Java 开发工具用于 Android 生成过程,因此应在开发计算机上安装 JDK。 Android 不使用库包和运行时。


什么是 Android SDK?

image.png

Java 库:这些库是 SDK 平台的一部分,是 Java 库的 Android 版本。 它们包含你期望任何新式库所具有的实用工具类型。 你可以将它们用于字符串处理、网络、数据结构等。 这些库是 Android 独有的。 它们与任何 Java 版本(J2ME、J2SE、J2EE)中的库都不同。


Android 库:这些库是 SDK 平台的一部分。 通过它们可以访问 Android 服务,以拨打电话、查找当前位置、启动活动等。


工具:有各种工具可以支持生成时和运行时。 此类别的一个示例是 DEX 编译器,它将标准 Java 字节码转换为 Android Dalvik Executable (DEX) 字节码。 另一个示例是 apkbuilder 打包工具,它将所有已编译的源代码集合到一个文件中。 此文件上传到 Play Store。


什么是 Android 本机开发工具包?

Android 本机开发工具包 (NDK) 包含一些用于将本机代码(如 C++)集成到 Android 应用程序中的工具。

image.png

本机代码直接在 Dalvik 虚拟机之外,在 Android 平台上运行。 拥有不希望移植到 Java 的现有 C++ 代码库时,NDK 非常有用。 可以使用 NDK 直接将基本代码合并到 Android 应用中。


什么是 Mono?

Mono 项目是 Microsoft .NET Framework 的开放源代码实现。

image.png

Xamarin.Android 使用许多 Mono 工具和库,因为 Mono 拥有生成多种应用所需的核心部分:

Mono 基类库 (BCL):BCL 与 .NET Framework 类库相同,包含所有常用实用工具类。 Xamarin.Android 包含 .NET Framework 类库的子集。 该子集包括 LINQ、任务、XML、Regex、I/O 和网络 API 等功能。

Mono 类库:此库提供标准 .NET Framework 范围以外的额外的类(例如,用于处理 zip 文件的类)。

Mono 运行时:Mono 运行时执行 Microsoft 中间语言 (MSIL)。 此 Mono 运行时版本专为 Xamarin.Android 自定义。 此运行时与 Java 运行时并行运行。 Mono 运行时提供类型检查、静态反射、互操作性和垃圾回收等应用功能。

C# 编译器:C# 编译器用于创建将用于执行应用的初始 MSIL。


本机 Java Android 如何编译代码?

本机 Android 应用主要使用 Java 编写。 Java 源代码编译为 Java 字节码。 Android 使用 JDK 中的标准 Java 编译器来编译代码。

image.png

然后 Java 字节码被转换为 Android 专有的字节码格式(称为 Dalvik 字节码)或 Dalvik Executable (DEX) 格式。


打包本机 Android 应用

Android 应用合并为一个文件以供部署。 可将此文件部署到设备或将其上传到 Android Play Store。

image.png

该文件称为应用程序包,扩展名为 .apk。 它包含应用的所有资产:


现为 DEX 字节码格式的可执行代码

现为二进制格式的布局文件

所有非代码资产,例如图像

NDK 预编译库(如果包含)

apkbuilder 创建 .apk 文件后,如果要将应用上传到 Play Store,还需要执行两个步骤:


使用 jarsigner 对 .apk 文件签名,以识别你(即应用发布者)。

运行 zipalign 修改 .apk 文件,使数据的初始边界为 4 字节。



了解本机执行

本机 Android 应用的执行引擎是 Android 运行时 (ART)。 安装应用时,ART 会将 .apk 文件中的字节码转换为本机代码。 仅进行一次转换。

Android 基于 Linux。 应用在自己的进程中运行并获得自己的 ART 副本。 独立的进程使应用彼此隔离。 这种隔离有助于提高安全性。


Xamarin.Android 如何编译代码?

Xamarin.Android 应用中的 C# 源代码编译为 MSIL 并打包成程序集。

image.png

Xamarin.Android 生成工具自动包含 .apk 文件中的 Mono 运行时。 Mono 运行时类似于 .NET 的公共语言运行时 (CLR)。 Mono 运行时具有 MSIL 编译器、垃圾回收器,等等。


Mono 运行时是应用执行中间语言 (IL) 的进程的一部分。

image.png

ART 是应用执行本机 Java 代码的进程的一部分。 例如,Xamarin.Android 库是基础 java.* 和 android.* Java 包的 C# 包装器。 这些包是本机 Android 类型,不是用 C# 编写的。 它们必须在 ART 上运行。

Mono 运行时和 ART 在应用进程中并行运行。


安装 Xamarin.Android

设置开发计算机时,将运行 Xamarin 统一安装程序。 应在 Windows 上安装 Visual Studio。 在 macOS 上,安装程序包含 Visual Studio for Mac。

image.png

安装程序将所有系统必备组件安装在你的计算机上:

    Java:JDK

    Android:SDK 和 NDK

    Xamarin:Xamarin.Android 和 Mono

当更新可用时,Xamarin 组件会主动通知你。 通知有助于使安装的 Xamarin 部分保持最新。


JDK 和 NDK 相当稳定,很少需要更新。 但是,Xamarin.Android 新版本有时需要更新 JDK。 例如,Android Designer 中的自定义控件需要 64 位版本的 JDK。

Android SDK 经常更新。 它在更新准备就绪时不会通知你。 你需要主动查找更新并手动开始安装。


更新 Android SDK

若要使用最新版本的 Android,需要在开发计算机上安装这些 Android 版本。

image.png

将更新两个关键部分:

    SDK 平台:此选项包含你需要编译的所有库。 SDK 平台包括 java.* 类型和 android.* 类型。 换句话说,这些类型是用于执行启动其他活动、拨打电话、访问文件系统、生成 UI 等操作的 Android API。

    工具:此选项包括许多可用于生成和运行应用的工具。

Android 版本由三个属性标识:

    代码名称

    版本号

    API 级别

什么是 Android SDK 管理器?

image.png

image.png

将仅为要使用的 API 级别安装 SDK 平台。 没有必要每一个都安装。 例如,几乎不需要安装和使用 API 级别 7,因为它已过时多年。


更新工具

Android 将工具拆分为三个可以独立更新的逻辑组。标准建议是使三个类别全部保持最新。 这些工具是向后兼容的,因此几乎不需要避免更新。

image.png

借助 Xamarin.Android,.NET 开发人员可以创建完全原生的 Android 应用。 开发人员可以获得 Android 平台强有力的支持,并充分利用其功能和性能。 在本模块中,你已经了解了 Xamarin.Android 及其开发工具,并生成了一个 Android 应用程序。



更多

Xamarin Android 应用程序基础知识 - Xamarin | Microsoft Docs

用 Xamarin 创建用户界面 - Xamarin | Microsoft Docs

Xamarin.Android 的平台功能 - Xamarin | Microsoft Docs

Android 穿戴设备 - Xamarin | Microsoft Docs

推荐您阅读更多有关于“vs2022xamarin,”的文章

猜你喜欢

额 本文暂时没人评论 来添加一个吧

发表评论

必填

选填

选填

必填

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

  查看权限

抖音:wpfui 工作wpf

目前在合肥企迈科技公司上班,加我QQ私聊

2023年11月网站停运,将搬到CSDN上

AYUI8全源码 Github地址:前往获取

杨洋(AaronYang简称AY,安徽六安人)AY唯一QQ:875556003和AY交流

高中学历,2010年开始web开发,2015年1月17日开始学习WPF

声明:AYUI7个人与商用免费,源码可购买。部分DEMO不免费

查看捐赠

AYUI7.X MVC教程 更新如下:

第一课 第二课 程序加密教程

标签列表