C# + WPF调用Web Api 自制B站客户端

C# + WPF调用Web Api 自制B站客户端_第1张图片

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
    {

        /// 
        /// 调用webapi通用方法(带Cookie)
        /// 
        /// 
        /// 
        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;
            });
        }

        /// 
        /// 调用webapi通用方法(带参数)
        /// 
        /// 
        /// 
        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);
    }

你可能感兴趣的:(WPF技术,开源库使用,自定义控件,c#,前端,开发语言)