C# + WPF自制B站客户端

已经开源,地址:Github地址
喜欢的话,请点个Star吧!!

最近无聊尝试调用Web API做个B站的客户端程序练练手,经过两天的摸索有了一些成果。主要的思路有如下几个:

  • 使用B站的Web扫描二维码接口,获取登录Cookie,再通过Cookie获取需要的信息
  • 使用ZXing开源库生成二维码图片
  • 使用WPF写程序的界面
  • 通过异步加载,实现列表的流畅显示
  • ListBox使用动画过渡实现更好的滑动效果

以后有时间的话,完整的分析一下项目,这里放出实现的一些界面和Web API调用的方法

ListBox 动画滑动效果

 public class AnimationScrollViewer : ScrollViewer{        //记录上一次的滚动位置private double LastLocation = 0;        //重写鼠标滚动事件protected override void OnMouseWheel(MouseWheelEventArgs e){double WheelChange = e.Delta;            //可以更改一次滚动的距离倍数 (WheelChange可能为正负数!)double newOffset = LastLocation - (WheelChange * 2);            //Animation并不会改变真正的VerticalOffset(只是它的依赖属性) 所以将VOffset设置到上一次的滚动位置 (相当于衔接上一个动画)            ScrollToVerticalOffset(LastLocation);            //碰到底部和顶部时的处理if (newOffset < 0)newOffset = 0; if (newOffset > ScrollableHeight)newOffset = ScrollableHeight;AnimateScroll(newOffset);LastLocation = newOffset;            //告诉ScrollViewer我们已经完成了滚动e.Handled = true;}private void AnimateScroll(double ToValue){            //为了避免重复,先结束掉上一个动画BeginAnimation(ScrollViewerBehavior.VerticalOffsetProperty, null);DoubleAnimation Animation = new DoubleAnimation();Animation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };Animation.From = VerticalOffset;Animation.To = ToValue;            //动画速度Animation.Duration = TimeSpan.FromMilliseconds(400);            //考虑到性能,可以降低动画帧数            //Timeline.SetDesiredFrameRate(Animation, 40);BeginAnimation(ScrollViewerBehavior.VerticalOffsetProperty, Animation);}}public static class ScrollViewerBehavior{public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerBehavior), new UIPropertyMetadata(0.0, OnVerticalOffsetChanged));public static void SetVerticalOffset(FrameworkElement target, double value) => target.SetValue(VerticalOffsetProperty, value);public static double GetVerticalOffset(FrameworkElement target) => (double)target.GetValue(VerticalOffsetProperty);private static void OnVerticalOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) => (target as ScrollViewer)?.ScrollToVerticalOffset((double)e.NewValue);}

ListBox 动画进入效果

   public class FadeAnimateItemsBehavior : Behavior<ItemsControl>{public DoubleAnimation Animation { get; set; }public ThicknessAnimation TaAnimation { get; set; }public TimeSpan Tick { get; set; }protected override void OnAttached(){base.OnAttached();AssociatedObject.Loaded += new System.Windows.RoutedEventHandler(AssociatedObject_Loaded);}void AssociatedObject_Loaded(object sender, System.Windows.RoutedEventArgs e){IEnumerable<ListBoxItem> items;if (AssociatedObject.ItemsSource == null){items = AssociatedObject.Items.Cast<ListBoxItem>();}else{var itemsSource = AssociatedObject.ItemsSource;if (itemsSource is INotifyCollectionChanged){var collection = itemsSource as INotifyCollectionChanged;collection.CollectionChanged += (s, cce) =>{if (cce.Action == NotifyCollectionChangedAction.Add){var itemContainer = AssociatedObject.ItemContainerGenerator.ContainerFromItem(cce.NewItems[0]) as ContentPresenter;if (itemContainer != null){itemContainer.BeginAnimation(ContentPresenter.OpacityProperty, Animation);itemContainer.BeginAnimation(ContentPresenter.MarginProperty, TaAnimation);}}};}ListBoxItem[] itemsSub = new ListBoxItem[AssociatedObject.Items.Count];for (int i = 0; i < itemsSub.Length; i++){itemsSub[i] = AssociatedObject.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;}items = itemsSub;}foreach (var item in items){if (item!=null)item.Opacity = 0;}var enumerator = items.GetEnumerator();if (enumerator.MoveNext()){DispatcherTimer timer = new DispatcherTimer() { Interval = Tick };timer.Tick += (s, timerE) =>{var item = enumerator.Current;if (item != null){item.BeginAnimation(ListBoxItem.OpacityProperty, Animation);item.BeginAnimation(ListBoxItem.MarginProperty, TaAnimation);}if (!enumerator.MoveNext()){timer.Stop();}};timer.Start();}}}

WebAPI调用:

public class WebApiRequest{/// <summary>/// 调用webapi通用方法(带Cookie)/// </summary>/// <param name="url"></param>/// <returns></returns>public async static Task<string> WebApiGetAsync(string url){return await Task.Run(() =>{string content = null;using (HttpClient httpclient = new HttpClient()){HttpRequestMessage msg = new HttpRequestMessage();msg.Method = HttpMethod.Get;msg.RequestUri = new Uri(url);if (SoftwareCache.CookieString != null){msg.Headers.Add("Cookie", SoftwareCache.CookieString);//cookie:SESSDATA=***}var result = httpclient.SendAsync(msg).Result;content = result.Content.ReadAsStringAsync().Result;}return content;});}/// <summary>/// 调用webapi通用方法(带参数)/// </summary>/// <param name="url"></param>/// <returns></returns>public async static Task<string> WebApiGetAsync(string url, Dictionary<string, string> para){return await Task.Run(() =>{string content = null;StringBuilder parastr = new StringBuilder("?");foreach (var item in para){parastr.Append(item.Key);parastr.Append("=");parastr.Append(item.Value);parastr.Append("&");}string paraResult = parastr.ToString().TrimEnd('&');using (HttpClient httpclient = new HttpClient()){HttpRequestMessage msg = new HttpRequestMessage();msg.Method = HttpMethod.Get;msg.RequestUri = new Uri(url + paraResult);if (SoftwareCache.CookieString != null){msg.Headers.Add("Cookie", SoftwareCache.CookieString);//cookie:SESSDATA=***}var result = httpclient.SendAsync(msg).Result;content = result.Content.ReadAsStringAsync().Result;}return content;});}public async static Task<string> PostHttpAsync(string url, string body, string contentType){return await Task.Run(() =>{HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);httpWebRequest.ContentType = contentType;httpWebRequest.Method = "POST";httpWebRequest.Timeout = 20000;byte[] btBodys = Encoding.UTF8.GetBytes(body);httpWebRequest.ContentLength = btBodys.Length;httpWebRequest.GetRequestStream().Write(btBodys, 0, btBodys.Length);HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();StreamReader streamReader = new StreamReader(httpWebResponse.GetResponseStream());string responseContent = streamReader.ReadToEnd();httpWebResponse.Close();streamReader.Close();httpWebRequest.Abort();httpWebResponse.Close();return responseContent;});}}

生成二维码

 public class QRCode{public static ImageSource CreateQRCode(string content, int width, int height){EncodingOptions options;//包含一些编码、大小等的设置BarcodeWriter write = null;//用来生成二维码,对应的BarcodeReader用来解码options = new QrCodeEncodingOptions{DisableECI = true,CharacterSet = "UTF-8",Width = width,Height = height,Margin = 0};write = new BarcodeWriter();write.Format = BarcodeFormat.QR_CODE;write.Options = options;IntPtr ip = write.Write(content).GetHbitmap();BitmapSource bitmapSource = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(ip, IntPtr.Zero, Int32Rect.Empty,System.Windows.Media.Imaging.BitmapSizeOptions.FromEmptyOptions());DeleteObject(ip);return bitmapSource;}// 注销对象方法API[DllImport("gdi32")]static extern int DeleteObject(IntPtr o);}

C# + WPF调用Web Api 自制B站客户端相关推荐

  1. 【ASP.NET Web API教程】3.3 通过WPF应用程序调用Web API(C#)

    注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. 3.3 Calling a Web API From a WPF Application ...

  2. python 图表_Python入门学习系列——使用Python调用Web API实现图表统计

    使用Python调用Web API实现图表统计 Web API:Web应用编程接口,用于URL请求特定信息的程序交互,请求的数据大多以非常易于处理的格式返回,比如JSON或CSV等. 本文将使用Pyt ...

  3. ASP.NET MVC4中调用WEB API的四个方法

    当今的软件开发中,设计软件的服务并将其通过网络对外发布,让各种客户端去使用服务已经是十分普遍的做法.就.NET而言,目前提供了Remoting,WebService和WCF服务,这都能开发出功能十分强 ...

  4. 利用Fiddler模拟通过Dynamics 365的OAuth 2 Client Credentials认证后调用Web API

    微软动态CRM专家罗勇 ,回复337或者20190521可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me. 配置Dynamics 365 & PowerApps 支 ...

  5. java 调用webapi json_java通过url调用web api并接收其返回的json

    java通过url调用webapi并接收其返回的json数据,但现在结果总是:{"result":4,"data":{}}(未认证:),帮助文档如下:API使用 ...

  6. jQuery跨域调用Web API

    我曾经发表了一篇关于如何开发Web API的博客,链接地址:http://www.cnblogs.com/guwei4037/p/3603818.html.有朋友说开发是会开发了,但不知道怎么调用啊? ...

  7. 使用HttpClient 调用Web Api

    C#4.5 添加了异步调用Web Api . 如果你的项目是4.5以上版本,可以直接参考官方文档. http://www.asp.net/web-api/overview/web-api-client ...

  8. android 调用 asp.net web api,从 .NET 客户端调用 Web API (C#)

    从 .NET 客户端调用 Web API (C#) 11/24/2017 本文内容 此内容适用于以前版本的 .NET. 新开发应该使用 ASP.NET Core. 有关使用 Core Web API ...

  9. WebApi系列~通过HttpClient来调用Web Api接口

    HttpClient是一个被封装好的类,主要用于Http的通讯,它在.net,java,oc中都有被实现,当然,我只会.net,所以,只讲.net中的HttpClient去调用Web Api的方法,基 ...

最新文章

  1. 中国移动与苹果联姻 三星在华霸主地位或遭取代
  2. git 修改仓库的描述_git简介、基本命令和仓库操作
  3. [SQL Server优化]善用系统监视器,确定系统瓶颈
  4. Linq to sql和lambda
  5. SAP ECC EHP7 RFC 发布成WebService
  6. Linux下查看某个进程的网络带宽占用情况
  7. 《编程原本 》一2.2 轨道
  8. MySQL SQL优化之覆盖索引
  9. Java集合框架——collections工具类
  10. Linux内核中获取虚拟机KVM结构体信息以及vCPU个数
  11. 电机与拖动:异步交流电动机改变电压,转子电阻及频率的机械特性曲线(Matlab实现方法)
  12. Iterative closest point (ICP) 算法
  13. bzoj 4987 Tree - dp
  14. 古墓丽影暗影显卡测试软件,游戏新消息:战地5古墓丽影暗影8K测试单显卡根本带不动...
  15. STM32(3)——外部中断的使用
  16. NLP 前置知识2 —— 深度学习算法
  17. 华为云计算之rainbow迁移实验
  18. CSS中IE和火狐对margin、padding的兼容性解析
  19. 如何构建语音识别能力?有哪些语音数据集?
  20. python正则匹配括号以及内容_【Python】正则表达式匹配最里层括号的内容

热门文章

  1. 显微镜下的webpack4:路径操作
  2. 计算机如何安装无线网络适配器,无线网络接收器怎么安装 无线网络接收器安装方法【详解】...
  3. word打开文件显示只读,如何对文档进行编辑的解决办法
  4. Miller gingival recession(牙龈退缩)与mucogingival junction(膜龈联合)
  5. python自动登录校园网 密码_python自动登陆校园网
  6. StarRocks SSD磁盘配置使用
  7. python问答系统实践
  8. 针孔相机模型和相机镜头畸变模型
  9. mybatis中小于等于的写法
  10. 如何使用 Python 验证电子邮件地址