概述
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站客户端C# + WPF自制B站客户端的全部内容,希望文章能够帮你解决C# + WPF调用Web Api 自制B站客户端C# + WPF自制B站客户端所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复