在前两篇老司机学Xamarin系列中,简单介绍了Xamarin开发环境的搭建以及Prism和MvvmCross这两个开发框架。不同的框架,往往不仅仅使用不同的架构风格,同时社区活跃度不同,各种功能模块和插件数量也会有巨大差别。架构风格的好坏,属于仁者见仁,但功能模块和插件的好坏多寡,却实实在在体现了社区的力量,是可以实打实拿出来练一练的。今天我们就来一起玩一玩MvvmCross提供的各种功能插件,看看哪些轮子可以拿来直接就用的。

备注:本文主要关注兼容Xamarin Forms xaml并且至少支持Droid和iOS平台的插件。

官方模块和插件

在把视线放到社区贡献的插件之前,我们先来看看,MvvmCross框架官方提供了哪些模块、插件:

Localization

Localization支持,对任何一个需要支持多国语言的App都必不可少。这个组件其实谈不上MvvmCross特有,基本上是Xamarin官方文档推荐的最佳实践。不过MvvmCross的VS项目模版直接包含了这个实现,并且集成到了MvvmCross自己的IoC容器的服务注册。

在MvvmCross模版生成的项目中,资源文件和获取device当前语言的ILocalizeService接口定义在PCL Core项目中:

特定平台的LocalizeService实现,定义在各自平台项目的Services目录中。在Setup类中默认将ILocalizeService注册成为Singleton:

在任意xaml的View中,通过{res:Translate ResourceKey}这样的格式绑定到控件的属性:

DataBinding

数据绑定,是对任何App的View的显示和交互必不可少的功能,这方面,Xamarin Forms本身的支持,就已经非常强悍了。MvvmCross有一个页面专门介绍它对数据绑定的增强,然而,几乎所有的增强貌似都是针对非Xamarin Forms xaml时期的Xamarin UI的数据绑定支持的,随着Forms基于xaml的本身的数据绑定能力的出现和不断增强,MvvmCross的这部分扩展其实已经过时了。

需要重点提及的是,在上面的LocalizeService组件的介绍中提到的{res:Translate ResourceKey}这样的语法,其实是基于Xamarin Forms官方的IMarkupExtension接口的扩展。而另一个可以用来扩展数据绑定的是IValueConverter接口。自定义的value converter,一般是用来在进行某个字段的数据的存储和数据的显示之间的转换的,但是,应该也可以利用它的语法来实现一些巧妙的数据绑定扩展。未来对Xamarin Forms UI组件的数据绑定的真正扩展,我想应该是基于上面提到的这两个接口来实现。期望以后能看到各种有趣的插件。当然,自己增加扩展也很容易。

简单举一个自定义IValueConverter的例子。假设我实现了下面这个自定义converter,用来自定义显示某个model的长度属性:

上面这个Converter的意思是,如果一个字段在ViewModel里面的属性值为空,或者为0,显示到页面上时,显示为Default,否则,显示原来的值。假设ViewModel包含下面这个Length属性,默认值为0:

xaml页面的一个Label的Text,现在要绑定到上面这个Length属性,并且,使用上面这个converter:

xaml里稍微复杂一点,不过也不难理解。首先是定义一个名叫local的xmlns,然后需要将这个自定义的converter注册到resource中,最后,在Label的Text属性中指定绑定和converter。

Accelerometer

Accelerometer插件读取Accelerometer传感器的值。因为肯定要访问设备特定的API,它自然包含接口和对应不同设备的具体实现。在项目中启用一个MvvmCross的plugin,只需引用对应的nuget package。这个插件对应的package是MvvmCross.Plugin.Accelerometer,可以从nuget.org下载。如果为一个包含shared PCL项目和Droid,iOS项目的solution添加这个插件的nuget package后,会看到,shared项目只自动引用了包含IMvxAccelerometer接口的dll,而Droid项目和iOS项目则还自动引用了实现了IMvxAccelerometer接口的平台特定的dll,并且,在Droid和iOS项目中的Boostrap目录,会自动添加一个AccelerometerPluginBootstrap类,这个类是用于在App启动时自动注册插件的,在这里,特定来说,Bootstrap内部会自动注册IMvxAccelerometer接口的实现。然后,我们就可以在代码里访问传感器的数据了。比如:

当访问设备特定的api时,还需要留意是否需要申请特定的设备权限。比如安卓设备访问Accelerometer就需要在Droid项目\Properties\AndroidManifest.xml文件中添加一个users-feature如下:

可以看到,MvvmCross插件的注册机制非常巧妙,我一开始以为可能每个插件至少需要有shared,droid,ios这样多个nuget package,实际上,它只有一个nuget package,不同的项目类型自动引用了同一个package里的不同target的dll,而且还自动添加了Bootstrap类,在框架层面通过反射和命名约定自动载入了插件,使得整个插件启用过程不需手写任何代码,非常赞!另外,除了通过Mvx.Resolve()获取一个接口的实例之外,MvvmCross也支持构造函数注入,比如,可以为ViewModel的构造函数,添加一个IMvxAccelerometer参数,当ViewModel被IoC容器初始化时,构造函数的参数都会被自动注入。

Email

Email插件,自然是用来发Email了。安装nuget package:MvvmCross.Plugins.Email。它就包含了下面这个接口:

  1. public interface IMvxComposeEmailTask
  2. {
  3. void ComposeEmail(string to, string cc, string subject, string body, bool isHtml);
  4. }

所以,发邮件至需要下面这样的代码,不能再简单了:

  1. Mvx.Resolve<IMvxComposeEmailTask>()
  2. .ComposeEmail("me@slodge.com",
  3. string.Empty,
  4. "MvvmCross Email",
  5. "I <3 MvvmCross",
  6. false);

File

File插件,提供了读写设备本地文件的能力。nuget package:MvvmCross.Plugins.File。Droid和iOS读写文件时默认的当前目录有差异(更多其他平台的当前目录,请参见官方文档):

  • Android - Context.FilesDir
  • iOS - Environment.SpecialFolder.MyDocuments

实现的接口如下:

  1. public interface IMvxFileStore
  2. {
  3. bool TryReadTextFile(string path, out string contents);
  4. bool TryReadBinaryFile(string path, out Byte[] contents);
  5. bool TryReadBinaryFile(string path, Func<Stream, bool> readMethod);
  6. void WriteFile(string path, string contents);
  7. void WriteFile(string path, IEnumerable<Byte> contents);
  8. void WriteFile(string path, Action<Stream> writeMethod);
  9. bool TryMove(string from, string to, bool deleteExistingTo);
  10. bool Exists(string path);
  11. bool FolderExists(string folderPath);
  12. string PathCombine(string items0, string items1);
  13. string NativePath(string path);
  14. void EnsureFolderExists(string folderPath);
  15. IEnumerable<string> GetFilesIn(string folderPath);
  16. void DeleteFile(string path);
  17. void DeleteFolder(string folderPath, bool recursive);
  18. }

具体使用方法类似其他插件,只需要通过Mvx.Resolve()方法拿到instance,调用相应方法即可,这里就不详述了。

Location

Location插件,用来获取用户当前的GPS位置信息。nuget package: MvvmCross.Plugins.Location。实现了IMvxLocationWatcher接口:

  1. public interface IMvxLocationWatcher
  2. {
  3. void Start(
  4. MvxLocationOptions options,
  5. Action<MvxGeoLocation> success,
  6. Action<MvxLocationError> error);
  7. void Stop();
  8. bool Started { get; }
  9. MvxGeoLocation CurrentLocation { get; }
  10. MvxGeoLocation LastSeenLocation { get; }
  11. event EventHandler<MvxValueEventArgs<MvxLocationPermission>> OnPermissionChanged;
  12. }

使用方式和Accelerometer类似,就不详述了。

Messenger

Messenger插件提供了基于内存的组件间基于消息的pub/sub功能。非常有用的一个插件。nuget package:MvvmCross.Plugins.Messenger。这是一个纯PCL插件,没有平台特定代码。实现了IMvxMessenger接口:

  1. public interface IMvxMessenger
  2. {
  3. MvxSubscriptionToken Subscribe<TMessage>(Action<TMessage> deliveryAction, MvxReference reference = MvxReference.Weak, string tag = null) where TMessage : MvxMessage;
  4. MvxSubscriptionToken SubscribeOnMainThread<TMessage>(Action<TMessage> deliveryAction, MvxReference reference = MvxReference.Weak, string tag = null) where TMessage : MvxMessage;
  5. MvxSubscriptionToken SubscribeOnThreadPoolThread<TMessage>(Action<TMessage> deliveryAction, MvxReference reference = MvxReference.Weak, string tag = null) where TMessage : MvxMessage;
  6. void Unsubscribe<TMessage>(MvxSubscriptionToken mvxSubscriptionId) where TMessage : MvxMessage;
  7. bool HasSubscriptionsFor<TMessage>() where TMessage : MvxMessage;
  8. int CountSubscriptionsFor<TMessage>() where TMessage : MvxMessage;
  9. bool HasSubscriptionsForTag<TMessage>(string tag) where TMessage : MvxMessage;
  10. int CountSubscriptionsForTag<TMessage>(string tag) where TMessage : MvxMessage;
  11. IList<string> GetSubscriptionTagsFor<TMessage>() where TMessage : MvxMessage;
  12. void Publish<TMessage>(TMessage message) where TMessage : MvxMessage;
  13. void Publish(MvxMessage message);
  14. void Publish(MvxMessage message, Type messageType);
  15. void RequestPurge(Type messageType);
  16. void RequestPurgeAll();
  17. }

Network

Network插件本来只是设计来检测某个网络主机是否能连通。结果,功能被热心网友不断扩充,就成了一个轻量级的REST Http Client。nuget package:MvvmCross.Plugins.Network。它提供了下面这些接口的实现:

  1. public interface IMvxReachability
  2. {
  3. bool IsHostReachable(string host);
  4. }
  5. public interface IMvxRestClient
  6. {
  7. void ClearSetting(string key);
  8. void SetSetting(string key, object value);
  9. IMvxAbortable MakeRequest(MvxRestRequest restRequest, Action<MvxRestResponse> successAction, Action<Exception> errorAction);
  10. IMvxAbortable MakeRequest(MvxRestRequest restRequest, Action<MvxStreamRestResponse> successAction, Action<Exception> errorAction);
  11. Task<MvxRestResponse> MakeRequestAsync(MvxRestRequest restRequest, CancellationToken cancellationToken = default(CancellationToken));
  12. Task<MvxStreamRestResponse> MakeStreamRequestAsync(MvxRestRequest restRequest, CancellationToken cancellationToken = default(CancellationToken));
  13. }
  14. public interface IMvxJsonRestClient
  15. {
  16. Func<IMvxJsonConverter> JsonConverterProvider { get; set; }
  17. IMvxAbortable MakeRequestFor<T>(MvxRestRequest restRequest, Action<MvxDecodedRestResponse<T>> successAction, Action<Exception> errorAction);
  18. Task<MvxDecodedRestResponse<T>> MakeRequestForAsync<T>(MvxRestRequest restRequest, CancellationToken cancellationToken = default(CancellationToken));
  19. }

PhoneCall

PhoneCall插件自然是用来打电话的。nuget package:MvvmCross.Plugins.PhoneCall。实现了IMvxPhoneCallTask接口:

  1. public interface IMvxPhoneCallTask
  2. {
  3. void MakePhoneCall(string name, string number);
  4. }

PictureChooser

PictureChooser用来从相册选照片,或者用相机拍照。nuget package:MvvmCross.Plugins.PictureChooser。实现了IMvxPictureChooserTask接口:

  1. public interface IMvxPictureChooserTask
  2. {
  3. void ChoosePictureFromLibrary(int maxPixelDimension, int percentQuality, Action<Stream> pictureAvailable, Action assumeCancelled);
  4. void TakePicture(int maxPixelDimension, int percentQuality, Action<Stream> pictureAvailable, Action assumeCancelled);
  5. }

简单的使用代码如下:

  1. var task = Mvx.Resolve<IMvxPictureChooserTask>();
  2. task.ChoosePictureFromLibrary(500, 90,
  3. stream => {
  4. // use the stream
  5. // expect the stream to be disposed after immediately this method returns.
  6. },
  7. () => {
  8. // perform any cancelled operation
  9. });

Share

Share插件用来发表分享。nuget package:MvvmCross.Plugins.Share。实现了IMvxShareTask接口:

  1. public interface IMvxShareTask
  2. {
  3. void ShareShort(string message);
  4. void ShareLink(string title, string message, string link);
  5. }

SQLite

SQLite插件是又一款必备插件,用来访问Sqlite数据库。nuget package:MvvmCross.Plugin.SQLitePCL。实现了IMvxSqliteConnectionFactory接口:

  1. public interface IMvxSqliteConnectionFactory
  2. {
  3. SQLiteConnection GetConnection(string databaseName, bool prefixPlatformPath = true);
  4. SQLiteConnection GetConnection(SqLiteConfig config, bool prefixPlatformPath = true);
  5. SQLiteAsyncConnection GetAsyncConnection(string databaseName, bool prefixPlatformPath = true);
  6. SQLiteAsyncConnection GetAsyncConnection(SqLiteConfig config, bool prefixPlatformPath = true);
  7. }

WebBrowser

WebBrowser插件调用外部浏览器显示一个页面。nuget package:MvvmCross.Plugins.WebBrowser。实现了IMvxWebBrowserTask接口:

  1. public interface IMvxWebBrowserTask
  2. {
  3. void ShowWebPage(string url);
  4. }

MvvmCross提供的官方插件,推荐的就这些了。貌似还有点不过瘾,好像很多期望的必备功能还没看到?下面来看看社区的贡献。

第三方插件

Settings

Settings插件提供了一个通用方案,用来持久化保存key/value键值对到各平台默认的App本地配置文件。nuget package:Cheesebaron.MvxPlugins.Settings。实现了ISettings接口:

  1. public interface ISettings
  2. {
  3. /// <param name="roaming">Roam settings (only for WindowsCommon)</param>
  4. T GetValue<T>(string key, T defaultValue = default(T), bool roaming = false);
  5. bool AddOrUpdateValue<T>(string key, T value = default(T), bool roaming = false);
  6. bool DeleteValue(string key, bool roaming = false);
  7. bool Contains(string key, bool roaming = false);
  8. bool ClearAllValues(bool roaming = false);
  9. }

DeviceInfo

DeviceInfo插件支持获取包括设备分辨率,设备id,固件版本,内存大小等等设备信息。nuget package:Cheesebaron.MvxPlugins.DeviceInfo。实现了IDeviceInfo和IDisplay接口:

  1. public interface IDeviceInfo
  2. {
  3. string DeviceId { get; }
  4. string Name { get; }
  5. string FirmwareVersion { get; }
  6. string HardwareVersion { get; }
  7. string Manufacturer { get; }
  8. string LanguageCode { get; }
  9. double TimeZoneOffset { get; }
  10. string TimeZone { get; }
  11. Orientation Orientation { get; }
  12. long TotalMemory { get; }
  13. bool IsTablet { get; }
  14. DeviceType DeviceType { get; }
  15. }
  16. public interface IDisplay
  17. {
  18. int Height { get; }
  19. int Width { get; }
  20. double Xdpi { get; }
  21. double Ydpi { get; }
  22. double Scale { get; }
  23. }

Connectivity

Connectivity插件返回当前设备是否联网,当前使用WIFI还是移动网络。nuget package:Cheesebaron.MvxPlugins.Connectivity。实现了IConnectivity接口:

  1. public interface IConnectivity: INotifyPropertyChanged
  2. {
  3. bool IsConnected { get; }
  4. bool IsWifi { get; }
  5. bool IsCellular { get; }
  6. Task<bool> GetHostReachableAsync(string host, CancellationToken token = default(CancellationToken));
  7. }

SMS

SMS插用来发送短信。nuget package:Cheesebaron.MvxPlugins.SMS。实现了ISmsTask接口:

  1. public interface ISmsTask
  2. {
  3. void SendSMS(string body, string phoneNumber);
  4. }

SecureStorage

SecureStorage插用用户保存敏感数据key/value键值对到平台特定的安全数据存储,比如Keychain,Password Vault等。nuget package:Beezy.MvvmCross.Plugins.SecureStorage。实现了IMvxProtectedData接口:

  1. public interface IMvxProtectedData
  2. {
  3. void Protect(string key, string value);
  4. string Unprotect(string key);
  5. void Remove(string key);
  6. }

InfiniteScrollPlugin

InfiniteScrollPlugin插用提供了一个能够根据指定的数据源,一直向下滚动分页显示数据的能力。nuget package:Sequence.Plugins.InfiniteScroll。实现了IIncrementalCollectionFactory接口。典型的示例可以参见这里

Fingerprint

Fingerprint提供指纹识别验证支持。nuget package:MvvmCross.Plugins.Fingerprint。实现了IFingerprint接口:

  1. Task<FingerprintAvailability> GetAvailabilityAsync();
  2. Task<bool> IsAvailableAsync();
  3. Task<FingerprintAuthenticationResult> AuthenticateAsync(string reason, CancellationToken cancellationToken = default(CancellationToken));
  4. Task<FingerprintAuthenticationResult> AuthenticateAsync(AuthenticationRequestConfiguration authRequestConfig, CancellationToken cancellationToken = default(CancellationToken));

调用IFingerprint接口的示例:

  1. var fpService = Mvx.Resolve<IFingerprint>(); // or use dependency injection and inject IFingerprint
  2. var result = await fpService.AuthenticateAsync("Prove you have mvx fingers!");
  3. if (result.Authenticated)
  4. {
  5. // do secret stuff :)
  6. }
  7. else
  8. {
  9. // not allowed to do secret stuff :(
  10. }

UserInteraction

UserInteraction插件实现了最常用的几个UserDialogs,包括:Alert,Confirm和Input。nuget package:Chance.MvvmCross.Plugins.UserInteraction。它实现了IUserInteraction接口:

  1. public interface IUserInteraction
  2. {
  3. void Confirm(string message, Action okClicked, string title = null, string okButton = "OK", string cancelButton = "Cancel");
  4. void Confirm(string message, Action<bool> answer, string title = null, string okButton = "OK", string cancelButton = "Cancel");
  5. Task<bool> ConfirmAsync(string message, string title = "", string okButton = "OK", string cancelButton = "Cancel");
  6. void Alert(string message, Action done = null, string title = "", string okButton = "OK");
  7. Task AlertAsync(string message, string title = "", string okButton = "OK");
  8. void Input(string message, Action<string> okClicked, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null);
  9. void Input(string message, Action<bool, string> answer, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null);
  10. Task<InputResponse> InputAsync(string message, string placeholder = null, string title = null, string okButton = "OK", string cancelButton = "Cancel", string initialText = null);
  11. void ConfirmThreeButtons(string message, Action<ConfirmThreeButtonsResponse> answer, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe");
  12. Task<ConfirmThreeButtonsResponse> ConfirmThreeButtonsAsync(string message, string title = null, string positive = "Yes", string negative = "No", string neutral = "Maybe");
  13. }

User Dialogs

User Dialogs严格来说并不是一个标准的MvvmCross插件。但是它提供了相比上面的UserInteraction更丰富的User Dialogs功能,所以,有需要的朋友也可以看一下。nuget package: Acr.UserDialogs。它可以和MvvmCrossy一起工作,但是没有follow MvvmCross插件自动初始化机制,因此,需要特别配置。引用package之后,需要在App类中注册IUserDialog到Mvx的IoC容器:

  1. Mvx.RegisterSingleton<IUserDialogs>(() => UserDialogs.Instance);

同时,对于Droid项目(iOS项目不需要),还必须在MvxFormsApplicationActivity类的OnCreate()方法里,执行下面的初始化代码:

  1. UserDialogs.Init(this);

然后,就可以在任意Command里调用IUserDialogs接口的方法弹出Dialogs了。IUserDialogs接口支持下面这些Dialogs方法:

  1. public interface IUserDialogs
  2. {
  3. IDisposable Alert(string message, string title = null, string okText = null);
  4. IDisposable Alert(AlertConfig config);
  5. Task AlertAsync(string message, string title = null, string okText = null, CancellationToken? cancelToken = null);
  6. Task AlertAsync(AlertConfig config, CancellationToken? cancelToken = null);
  7. IDisposable ActionSheet(ActionSheetConfig config);
  8. Task<string> ActionSheetAsync(string title, string cancel, string destructive, CancellationToken? cancelToken = null, params string[] buttons);
  9. IDisposable Confirm(ConfirmConfig config);
  10. Task<bool> ConfirmAsync(string message, string title = null, string okText = null, string cancelText = null, CancellationToken? cancelToken = null);
  11. Task<bool> ConfirmAsync(ConfirmConfig config, CancellationToken? cancelToken = null);
  12. IDisposable DatePrompt(DatePromptConfig config);
  13. Task<DatePromptResult> DatePromptAsync(DatePromptConfig config, CancellationToken? cancelToken = null);
  14. Task<DatePromptResult> DatePromptAsync(string title = null, DateTime? selectedDate = null, CancellationToken? cancelToken = null);
  15. IDisposable TimePrompt(TimePromptConfig config);
  16. Task<TimePromptResult> TimePromptAsync(TimePromptConfig config, CancellationToken? cancelToken = null);
  17. Task<TimePromptResult> TimePromptAsync(string title = null, TimeSpan? selectedTime = null, CancellationToken? cancelToken = null);
  18. IDisposable Prompt(PromptConfig config);
  19. Task<PromptResult> PromptAsync(string message, string title = null, string okText = null, string cancelText = null, string placeholder = "", InputType inputType = InputType.Default, CancellationToken? cancelToken = null);
  20. Task<PromptResult> PromptAsync(PromptConfig config, CancellationToken? cancelToken = null);
  21. IDisposable Login(LoginConfig config);
  22. Task<LoginResult> LoginAsync(string title = null, string message = null, CancellationToken? cancelToken = null);
  23. Task<LoginResult> LoginAsync(LoginConfig config, CancellationToken? cancelToken = null);
  24. IProgressDialog Progress(ProgressDialogConfig config);
  25. IProgressDialog Loading(string title = null, Action onCancel = null, string cancelText = null, bool show = true, MaskType? maskType = null);
  26. IProgressDialog Progress(string title = null, Action onCancel = null, string cancelText = null, bool show = true, MaskType? maskType = null);
  27. void ShowLoading(string title = null, MaskType? maskType = null);
  28. void HideLoading();
  29. void ShowImage(IBitmap image, string message, int timeoutMillis = 2000);
  30. void ShowSuccess(string message, int timeoutMillis = 2000);
  31. void ShowError(string message, int timeoutMillis = 2000);
  32. IDisposable Toast(string title, TimeSpan? dismissTimer = null);
  33. IDisposable Toast(ToastConfig cfg);
  34. }

AudioPlay

比较遗憾的是没有看到支持音乐播放(比如播放在线或本地的mp3/wav)的插件。这个应该是大多数App都需要的功能。搜索了一些网上的实现方案,先给需要的朋友做个参考,要不下次咱把它改造成标准的MvvmCross插件?

2016-10-22 Update: 兑现设想,我的第一个MvvmCross跨平台插件:SimpleAudioPlayer

2016-10-23 Update: 新增一些非MvvmCross,但是Xamarin下的通用第三方组件:

  • Xamarin-Forms-Labs - 看上去是Xamarin界最大的一个第三方组件库,包含了大量UI和Service等类型的好东西,组件列表太长了,不贴在这里,大家可以点过去看。
  • DLToolkit.Forms.Controls - DL Toolkit提供的几个非常酷的组件,包括图片转换、增强的ListView和tag标签功能等。
  • DevExpress-Grid - 老牌大厂DevExpress出的Xamarin Forms数据表格控件,功能强大,竟然完全免费?!

暂时就这些了。如果您发现有别的优秀插件,欢迎推荐,我也会持续补充进来。

老司机学新平台 - Xamarin Forms开发框架之MvvmCross插件精选的更多相关文章

  1. 老司机学新平台 - Xamarin Forms开发框架二探 (Prism vs MvvmCross)

    在上一篇Xamarin开发环境及开发框架初探中,曾简单提到MvvmCross这个Xamarin下的开发框架.最近又评估了一些别的,发现老牌Mvvm框架Prism现在也支持Xamarin Forms了, ...

  2. 老司机学新平台 - Xamarin开发之我的第一个MvvmCross跨平台插件:SimpleAudioPlayer

    大家好,老司机学Xamarin系列又来啦!上一篇MvvmCross插件精选文末提到,Xamarin平台下,一直没找到一个可用的跨平台AudioPlayer插件.那就自力更生,让我们就自己来写一个吧! ...

  3. 老司机学新平台 - Xamarin开发环境及开发框架初探

    随着被微软收购,最近一年间,Xamarin的火爆程度与日俱增.免费.更好的VS2015集成.更好的模拟器,甚至,在windows上运行和调试iOS平台程序,让我这样接触了十几年.NET平台的老司机,即 ...

  4. 老司机学Xamarin系列总目录

    Xamarin开发环境及开发框架初探 Xamarin Forms开发框架二探 (Prism vs MvvmCross) Xamarin Forms开发框架之MvvmCross插件精选 Xamarin开 ...

  5. C语言老司机学Python (五)

    今天看的是标准库概览. 操作系统接口: 用os模块实现. 针对文件和目录管理,还有个shutil模块可以用. 例句: import os os.getcwd() # 返回当前的工作目录 os.chdi ...

  6. Xamarin.Forms弹出对话框插件

    微信公众号:Dotnet9,网站:Dotnet9,问题或建议,请网站留言: 如果您觉得Dotnet9对您有帮助,欢迎赞赏. Xamarin.Forms弹出对话框插件 内容目录 实现效果 业务场景 编码 ...

  7. C语言老司机学Python (一)

    Python 版本:3.6.4 参考网上教程:http://www.runoob.com/python3/python3-basic-syntax.html 开始了啊. 干咱们这行的老规矩,学新语言的 ...

  8. xamarin.forms之使用CarouselView插件模仿网易新闻导航

    在APP中基本都能见到类似网易.今日头条等上边横向导航条,下边是左右滑动的页面,之前做iOS的时候模仿实现过,https://github.com/ywcui/ViewPagerndicator,在做 ...

  9. C语言老司机学Python (六)- 多线程

    前面的1-5都是比较基础的东西,能做的事情也有限. 从本节起,随着更多进阶技术的掌握,渐渐就可以用Python开始浪了. Python3使用threading模块来实现线程操作. 根据在其他语言处学来 ...

随机推荐

  1. Arduino uno 教程~持续更新~

    http://arduino.osall.com/index.html http://study.163.com/search.htm?t=2&p=Arduino http://www.ard ...

  2. HDU 3535 AreYouBusy (混合背包)

    题意:给你n组物品和自己有的价值s,每组有l个物品和有一种类型: 0:此组中最少选择一个 1:此组中最多选择一个 2:此组随便选 每种物品有两个值:是需要价值ci,可获得乐趣gi 问在满足条件的情况下 ...

  3. Maven的配置和使用(三)

    下面记录下如何使用Maven进行jar包的管理和更新. 在Maven中我们是通过对pom.xml文件的配置来对项目的包进行管理的,找到该文件并打开: <project xmlns="h ...

  4. 無間道III 終極無間

    凭良心说,它绝对算是诚意之作,而非急功近利或者说抢市.因为导演尤其是编剧都用了心,为了和第一二集融合而在细节处理上做足了文章,麦兆辉也实在够天才. 关于时间问题,本片不是完全杂乱无章,只不过是前后两段 ...

  5. 深入理解Java的接口和抽象类(转)

    深入理解Java的接口和抽象类 对于面向对象编程来说,抽象是它的一大特征之一.在Java中,可以通过两种形式来体现OOP的抽象:接口和抽象类.这两者有太多相似的地方,又有太多不同的地方.很多人在初学的 ...

  6. 如何创建独立的UE4服务端

    原文作者:@玄冬Wong 转载请注明原文出处:http://aigo.iteye.com/blog/2268777 这是论坛上对UE服务端功能的回答,意思是UE4提供了主流MMO网游服务端所具备的特性 ...

  7. Android 开源项目及其学习

    Android 系统研究:http://blog.csdn.net/luoshengyang/article/details/8923485 Android 腾讯技术人员博客 http://hukai ...

  8. Python调用HTTP接口并传递cookie

    #get接口调用 import urllib import urllib2 get_url = "http://10.10.3.63/test?id=123&name=nba&quo ...

  9. 页面加载完成后,触发事件——trigger()

    <button id="btn">点击我</button> <div id="test"></div> 如果页面 ...

  10. 一张图系列——为什么在DllMain里面创建了线程并Wait会卡死

    这是一个老话题了,推荐一篇文章: http://blog.csdn.net/breaksoftware/article/details/8150476#0-tsina-1-83826-39723281 ...