zoukankan      html  css  js  c++  java
  • C#的Xamarin开发小米盒子应用并以WCF实现微信通知

    对于熟悉C#语言的开发人员而言,用Xamarin开发Android应用也是一个不错的选择。小米盒子是Android系统。当然也就能够使用Xamarin来开发。首选来看效果图。


    注:(1).左图是从数据库中拉取用户列表(图中的用户的虚拟的)

    (2)中间图是依据选中的用户发起微信通知

    (3)右图是微信企业号中收到的通知

    一、在VS中建立Android应用

    1.布局主界面

    <?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">
        <LinearLayout
            android:orientation="horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">
            <Button
                android:id="@+id/btnLoadUser"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/LoadUser" />
            <Button
                android:id="@+id/btnWeiXinNotify"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/WeiXinNotify" />
            <Button
                android:id="@+id/btnClear"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/Clear" />
        </LinearLayout>
        <ListView
            android:minWidth="25px"
            android:minHeight="25px"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/listView1" />
    </LinearLayout>

    注:因为小米盒子使用的遥控器控制,不像手机是触摸屏的。所以界面中尽量以button、简易图表的形式展现。以方便控制。


    2.主界面MainActivity的CS代码

    using System;
    using Android.App;
    using Android.Content;
    using Android.Runtime;
    using Android.Views;
    using Android.Widget;
    using Android.OS;
    using System.Data;
    using System.Data.SqlClient;
    using System.Collections.Generic;
    using System.Text;
    
    namespace XiaoMiBoxDemo
    {
        [Activity(Label = "小米盒子应用演示样例", MainLauncher = true, Icon = "@drawable/icon")]
        public class MainActivity : Activity
        {
            private Button _btnLoadUser = null;
            private Button _btnWeiXinNotify = null;
            private Button _btnClear = null;
            private ListView _listView = null;
            private List<UserInfo> _userList = null;
    
            protected override void OnCreate(Bundle bundle)
            {
                base.OnCreate(bundle);
    
                SetContentView(Resource.Layout.Main);
                FetchControls();
                BindEvents();
            }
    
            private void BindEvents()
            {
                _btnLoadUser.Click += _btnLoadUser_Click;
                _listView.ItemClick += _listView_ItemClick;
                _btnWeiXinNotify.Click += _btnWeiXinNotify_Click;
                _btnClear.Click += _btnClear_Click;
            }
    
            void _btnClear_Click(object sender, EventArgs e)
            {
                _listView.Adapter = null;
                _userList.Clear();
            }
    
            void _btnWeiXinNotify_Click(object sender, EventArgs e)
            {
                if (_userList == null || _userList.Count <= 0)
                {
                    Toast.MakeText(this, "请选择要通知的用户", ToastLength.Long).Show();
                    return;
                }
    
                String qyNoIds = "";
                bool hasSelectedUser = false;
                foreach (UserInfo _userInfo in _userList)
                {
                    if (!_userInfo.IsSelected)
                    {
                        continue;
                    }
                    hasSelectedUser = true;
                    if (String.IsNullOrWhiteSpace(_userInfo.QYNo))
                    {
                        continue;
                    }
    
                    if (String.IsNullOrWhiteSpace(qyNoIds))
                    {
                        qyNoIds = _userInfo.QYNo;
                    }
                    else
                    {
                        qyNoIds += "|" + _userInfo.QYNo;
                    }
                }
    
                if (String.IsNullOrWhiteSpace(qyNoIds))
                {
                    if (hasSelectedUser)
                    {
                        Toast.MakeText(this, "所选择的用户没有绑定企业号", ToastLength.Long).Show();
                    }
                    else
                    {
                        Toast.MakeText(this, "请选择要通知的用户", ToastLength.Long).Show();
                    }
                    return;
                }
                String returnErrorMsg = "";
                EditText editText = new EditText(this);
                AlertDialog.Builder builder = new AlertDialog.Builder(this);
                builder.SetTitle("通知信息");
                builder.SetView(editText);
                EventHandler<DialogClickEventArgs> okClick = delegate
                {
                    String message = editText.Text;
                    if (WeiXinHelper.SendContent(out returnErrorMsg, qyNoIds, message))
                    {
                        returnErrorMsg = "发送成功";
                    }
                    Toast.MakeText(this, returnErrorMsg, ToastLength.Long).Show();
                };
                builder.SetNegativeButton("取消", delegate { });
                builder.SetPositiveButton("确定", okClick);
    
                builder.Show();
            }
    
    
            void _listView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
            {
                UserInfo userInfo = _userList[e.Position];
                userInfo.IsSelected = (!userInfo.IsSelected);
                String guid = String.Format("{0}", e.View.Tag);
                if (guid.Equals(userInfo.Guid))
                {
                    e.View.FindViewById<CheckBox>(Resource.Id.checkBoxUser).Checked = userInfo.IsSelected;
                }
            }
    
            private void FetchControls()
            {
                _btnLoadUser = FindViewById<Button>(Resource.Id.btnLoadUser);
                _btnWeiXinNotify = FindViewById<Button>(Resource.Id.btnWeiXinNotify);
                _btnClear = FindViewById<Button>(Resource.Id.btnClear);
                _listView = FindViewById<ListView>(Resource.Id.listView1);
            }
    
            void _btnLoadUser_Click(object sender, EventArgs e)
            {
                try
                {
                    String sql = " SELECT * FROM TUser ";
                    DataTable dt = DBUtil.Query(sql).Tables[0];
                    String account = "";
                    String nickname = "";
                    String qyNo = "";
                    String guid = "";
                    _userList = new List<UserInfo>();
                    foreach (DataRow row in dt.Rows)
                    {
                        guid = String.Format("{0}", row["u_guid"]);
                        account = String.Format("{0}", row["u_account"]);
                        nickname = String.Format("{0}", row["u_nickname"]);
                        qyNo = String.Format("{0}", row["u_qyNo"]);
                        _userList.Add(new UserInfo()
                        {
                            Guid = guid,
                            Account = account,
                            Nickname = nickname,
                            QYNo = qyNo,
                            IsSelected = false
                        });
                    }
                    _listView.Adapter = new UserListAdapter(this, _userList);
                }
                catch (Exception ex)
                {
                    Toast.MakeText(this, ex.Message, ToastLength.Long).Show();
                }
            }
        }
    }
    

    注:(1)使用自己定义的DBUtil类来查询数据库。

    (2)_listView使用自己定义的UserListAdapter来绑定数据。

    (3)给对应的button和_listView的项加入点击事件

    (3)须要特别注意的是MainActivity定义的上一行有 [Activity(Label = "小米盒子应用演示样例", MainLauncher = true, Icon = "@drawable/icon")]的代码,这里的Label将会影响到终于应用显示的名称(包含应用列表和应用启动后的),而icon在更换了之后。除了在项目属性中调整之外,这里也要一并调整,否则会编译只是。

    3.数据库工具类DBUtil

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;
    
    namespace XiaoMiBoxDemo
    {
        public class DBUtil
        {
            private static String ConnectionString = "server=数据库server;database=DBDemo;uid=sa;pwd=abc;pooling=false;Connect Timeout=120;";
    
            /// <summary>
            /// 运行查询语句。返回DataSet
            /// </summary>
            /// <param name="SQLString">查询语句</param>
            /// <returns>DataSet</returns>
            public static DataSet Query(string SQLString)
            {
                using (SqlConnection connection = new SqlConnection(ConnectionString))
                {
                    DataSet ds = new DataSet();
                    try
                    {
                        connection.Open();
                        SqlDataAdapter command = new SqlDataAdapter(SQLString, connection);
                        command.Fill(ds, "ds");
                    }
                    catch (System.Data.SqlClient.SqlException ex)
                    {
                        throw new Exception(ex.Message);
                    }
                    return ds;
                }
            }
        }
    }
    
    注:(1).数据库server。须要换成对应的值。比方192.168.1.101或www.xxx.com:8090等

         (2).C#下的Android连接数据库时,直接使用.Net的数据库连接方式。不必像eclipse下那么麻烦。只是须要注意,记得要引用对应的DLL(System.Data).该DLL一定要引用Android下的,而不.Net下的。这是我的Android的System.Data.dll路径C:Program Files (x86)Reference AssembliesMicrosoftFrameworkMonoAndroidv1.0System.Data.dll。

        (3).记得设置Android应用的编码。否则在运行SQL时可能会出现"Code page 936 not support"。这是由于我们开发的应用的字符集和数据库server的字符集不一致造成的。


    从图上能够看到SQLserver使用的Chinese_PRC_CI_AS的排序规则。这是GBK的字符集,所以我们的应用也需需有这种字符集支持,为此须要给应用加一个配置,见下图。项目->右键->属性,然后按下图配置。


    注:CJK表示的中日韩的字符集。

    4.列表适配器UserListAdapter

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using Android.App;
    using Android.Views;
    using Android.Widget;
    
    namespace XiaoMiBoxDemo
    {
        public class UserListAdapter : BaseAdapter<UserInfo>
        {
            /// <summary>
            /// 全部UserInof 的数据
            /// </summary>
            List<UserInfo> items;
    
            Activity context;
    
            public UserListAdapter(Activity context, List<UserInfo> items)
                : base()
            {
                this.context = context;
                this.items = items;
            }
    
            public override long GetItemId(int position)
            {
                return position;
            }
            public override UserInfo this[int position]
            {
                get { return items[position]; }
            }
            public override int Count
            {
                get { return items.Count; }
            }
    
            /// <summary>
            /// 系统会呼叫 而且render.
            /// </summary>
            /// <param name="position"></param>
            /// <param name="convertView"></param>
            /// <param name="parent"></param>
            /// <returns></returns>
            public override View GetView(int position, View convertView, ViewGroup parent)
            {
                var item = items[position];
                var view = convertView;
                if (view == null)
                {
                    //使用自订的UserListItemLayout
                    view = context.LayoutInflater.Inflate(Resource.Layout.UserListItemLayout, null);
                }
    
                view.FindViewById<TextView>(Resource.Id.textViewAccount).Text = item.Account;
                view.FindViewById<TextView>(Resource.Id.textViewNickname).Text = item.Nickname;
                view.FindViewById<TextView>(Resource.Id.textViewQYNo).Text = item.QYNo;
                view.FindViewById<CheckBox>(Resource.Id.checkBoxUser).Checked = item.IsSelected;
                view.Tag = item.Guid;
                return view;
            }       
        }
    }
    

    当中UserInfo的代码例如以下

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    
    namespace XiaoMiBoxDemo
    {
        public class UserInfo
        {
            /// <summary>
            /// Guid
            /// </summary>
            public String Guid { get; set; }
    
            /// <summary>
            /// 帐号
            /// </summary>
            public String Account { get; set; }
    
            /// <summary>
            /// 昵称
            /// </summary>
            public String Nickname { get; set; }
    
            /// <summary>
            /// 企业号
            /// </summary>
            public String QYNo { get; set; }
    
            /// <summary>
            /// 是否选中
            /// </summary>
            [DefaultValue(false)]
            public bool IsSelected { get; set; }
        }
    }
    


    以下是每个Item的布局代码

    <?

    xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" android:paddingLeft="10px"> <CheckBox android:text="" android:layout_width="wrap_content" android:layout_height="wrap_content" android:focusable="false" android:id="@+id/checkBoxUser" /> <LinearLayout android:orientation="vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:text="@string/Account" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:text="Text" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textViewAccount" /> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:text="@string/Nickname" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:text="Text" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textViewNickname" /> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content"> <TextView android:text="@string/QYNo" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <TextView android:text="Text" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textViewQYNo" /> </LinearLayout> </LinearLayout> </LinearLayout>

    5.字符串变量Strings.xml

    <?

    xml version="1.0" encoding="utf-8"?

    > <resources> <string name="LoadUser">用户列表</string> <string name="WeiXinNotify">微信通知</string> <string name="Clear">清空列表</string> <string name="ApplicationName">小米盒子应用演示样例</string> <string name="Account">帐号:</string> <string name="Nickname">昵称:</string> <string name="QYNo">企业号:</string> </resources>


    二.WCF实现微信通知

    1.原理:在实现了微信企业号的WCF服务后。在Android端以Web服务调用的形式来发起通知。

    2.引用WCF

    在WinForm或者Asp.Net下调用WCF。仅仅须要直接加入服务引用就能够了。在Xamarin下也是假设,所不同的是,这里加入的是Web引用。见下图。



    这时在我们的项目中,会多一个Web References的目录。以下会有一个WeiXinService,见下图。


    3.调用WCF

    为了方便以后调用,这里将调用封装到WeiXinHelper类中,代码例如以下

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace XiaoMiBoxDemo
    {
        #region WeiXinMessageType
        /// <summary>
        /// 微信的消息类型
        /// </summary>
        public sealed class WeiXinMessageType
        {
            public const string TEXT = "text";
        }
        #endregion
    
        #region WeiXinMessageEncription
        /// <summary>
        /// 微信的消息加密开关
        /// </summary>
        public sealed class WeiXinMessageEncription
        {
            /// <summary>
            /// 不须要加密
            /// </summary>
            public const string NOT = "0";
    
            /// <summary>
            /// 须要加密
            /// </summary>
            public const string NEED = "1";
        }
        #endregion
    
        public class WeiXinHelper
        {
            /// <summary>
            /// 发送文本消息给微信用户
            /// </summary>
            /// <param name="returnErrorMsg">当返回值为false时,返回的错误信息.</param>
            /// <param name="qyNoIds">用户的企业号的ID列表(多个用户之间用‘|’分隔)</param>
            /// <param name="message">发送的消息</param>
            /// <returns></returns>
            public static bool SendContent(out String returnErrorMsg, String qyNoIds, String message)
            {
                if (String.IsNullOrWhiteSpace(qyNoIds))
                {
                    returnErrorMsg = "缺少微信用户";
                    return false;
                }
    
                WeiXinService.MainService mainService = new WeiXinService.MainService();
                bool isSendMsgResult = false;
                bool isSendMsgResultSpecified = false;
                mainService.SendMsg(qyNoIds,
                                         null,
                                         null,
                                         WeiXinMessageType.TEXT,
                                         message,
                                         WeiXinMessageEncription.NOT,
                                         out isSendMsgResult,
                                         out isSendMsgResultSpecified,
                                         out returnErrorMsg);
    
                if isSendMsgResult&& isSendMsgResultSpecified,
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
    
    注:

    (1).这里调用WCF时不像Asp.Net或者WinForm下。使用Client来调用。而是要使用MainService实例来调用。为什么使用MainService呢?由于WCF的微信企业号服务主类就是MainService.

    (2).MainService中的SendMsg方法。原来有一个bool的返回值,可是这里不见了。事实上不是不见了,而是以out的形式输出了。

    即isSendMsgResult和isSendMsgResultSpecified.当中isSendMsgResultSpecified是引用时自己主动带入的參数。当isSendMsgResult和isSendMsgResultSpecified都为true时。表示成功。

    三.生成应用

    1.在生成应用之前,一定记得设置应用的api级别。并配置所须要的相关权限,详细见以下的图。

    注:假设没有配置Android的API级别,将会导致应用安装时程序包解析失败而无法安装。



    注:这里须要配置ACCESS_WIFI_STATE和INTERNAL的权限,假设没有配置将会导致数据库连接和微信通知时失败,提示connect refuse等字样。

    2.一定记得设置成Release下生成应用。在Debug下生成的应用可能正常执行的,在Release下可能会失败,最常见的就是权限没有设置导致的。

    3.应用可能须要配置合适的屏幕尺寸,否则在小米盒子中会无法显示,比方一片黑。

    3.打包应用


    转载请注明出处http://blog.csdn.net/xxdddail/article/details/46707481。



  • 相关阅读:
    CMDB服务器管理系统【s5day92】:服务器管理回顾
    主机管理+堡垒机系统开发:需求讨论(一)
    saltstack主机管理项目:今日总结(六)
    saltstack主机管理项目:动态调用插件解析-模块解析(五)
    saltstack主机管理项目:编写插件基类-获取主机列表-提取yaml配置文件(四)
    saltstack主机管理项目:计主机管理项目命令分发器(三)
    saltstack主机管理项目:主机管理项目需求分析(一)
    saltstack主机管理项目:主机管理项目架构设计(二)
    CMDB服务器管理系统【s5day89】:采集资产之整合资产
    CMDB服务器管理系统【s5day89】:采集资产之汇报信息
  • 原文地址:https://www.cnblogs.com/cynchanpin/p/6785730.html
Copyright © 2011-2022 走看看