XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEToolBox

完善主页轮播图的图片获取功能

2ac5528
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

11 个文件 +144 -68
Modified XFEToolBox/Profiles/CacheProfiles/AppCacheProfile.cs +2 -2
@@ -3,10 +3,10 @@ using XFEToolBox.Core.Model;
3 3
4 4 namespace XFEToolBox.Profiles.CacheProfiles;
5 5
6 public partial class AppCacheProfile
6 public partial class AppCacheProfile : XFEProfile
7 7 {
8 8 [ProfileProperty]
9 9 private string noticeText = "";
10 public AppCacheProfile() => ProfilePath = @$"{AppPath.CacheProfile}\{typeof(AppCacheProfile)}.xprofile";
11 10
11 public AppCacheProfile() => ProfilePath = @$"{AppPath.CacheProfile}\{typeof(AppCacheProfile)}.xprofile";
12 12 }
Modified XFEToolBox/Profiles/CrossVersionProfiles/ConsoleProfile.cs +1 -1
@@ -3,7 +3,7 @@ using XFEToolBox.Core.Model;
3 3
4 4 namespace XFEToolBox.Profiles.CrossVersionProfiles;
5 5
6 public partial class ConsoleProfile
6 public partial class ConsoleProfile : XFEProfile
7 7 {
8 8 /// <summary>
9 9 /// 控制台端口
Modified XFEToolBox/Profiles/CrossVersionProfiles/DownloadProfile.cs +1 -1
@@ -3,7 +3,7 @@ using XFEToolBox.Core.Model;
3 3
4 4 namespace XFEToolBox.Profiles.CrossVersionProfiles;
5 5
6 public partial class DownloadProfile
6 public partial class DownloadProfile : XFEProfile
7 7 {
8 8 /// <summary>
9 9 /// 是否使用一般的下载方式
Modified XFEToolBox/Profiles/CrossVersionProfiles/SystemProfile.cs +1 -1
@@ -4,7 +4,7 @@ using XFEToolBox.Views.Windows;
4 4
5 5 namespace XFEToolBox.Profiles.CrossVersionProfiles;
6 6
7 public partial class SystemProfile
7 public partial class SystemProfile : XFEProfile
8 8 {
9 9 /// <summary>
10 10 /// 当前窗口DPI缩放
Added XFEToolBox/Utilities/Helpers/BilibiliHelper.cs +17 -0
@@ -0,0 +1,17 @@
1 using System.Net.Http;
2 using XFEExtension.NetCore.XFETransform.JsonConverter;
3
4 namespace XFEToolBox.Utilities.Helpers;
5
6 public static class BilibiliHelper
7 {
8 public static async Task<List<Dictionary<string, ValueNode>>> GetSeasonVideoList(string seasonId = "3641758")
9 {
10 var client = new HttpClient();
11 client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 Edg/145.0.0.0");
12 QueryableJsonNode jsonNode = await client.GetStringAsync($"https://api.bilibili.com/x/polymer/web-space/seasons_archives_list?mid=200494622&season_id={seasonId}&sort_reverse=false&page_size=30&page_num=1&web_location=333.1387");
13 if (jsonNode["data"]?["archives"]?["package:list", "aid", "bvid", "pic", "title"].PackageInListObject() is List<Dictionary<string, ValueNode>> subJsonNodes)
14 return subJsonNodes;
15 return [];
16 }
17 }
Modified XFEToolBox/ViewModel/Pages/MainPageViewModel.cs +20 -1
@@ -1,7 +1,26 @@
1 1 using CommunityToolkit.Mvvm.ComponentModel;
2 using System.Windows.Media;
3 using System.Windows.Media.Imaging;
4 using XFEToolBox.Utilities.Helpers;
5 using XFEToolBox.Views.Pages;
2 6
3 7 namespace XFEToolBox.ViewModel.Pages;
4 8
5 9 public partial class MainPageViewModel : ObservableObject
6 10 {
7 }
11 public MainPage MainPage { get; set; }
12 public MainPageViewModel(MainPage mainPage)
13 {
14 MainPage = mainPage;
15 MainPage.Loaded += MainPage_Loaded;
16 }
17
18 private async void MainPage_Loaded(object sender, System.Windows.RoutedEventArgs e)
19 {
20 var videoInfoList = await BilibiliHelper.GetSeasonVideoList();
21 foreach (var videoInfo in videoInfoList)
22 {
23 MainPage.mainCarousel.AddItem(new BitmapImage(new Uri(videoInfo["pic"].ToString())), videoInfo["title"].ToString());
24 }
25 }
26 }
Modified XFEToolBox/Views/Controls/Carousel.xaml +36 -14
@@ -25,7 +25,11 @@
25 25 <!-- Center card column with rounded border and image -->
26 26 <Border Grid.Column="1" CornerRadius="12" Background="#F0EEF6" Padding="8">
27 27 <Grid>
28 <Image x:Name="PART_Image" Source="{Binding CurrentImageSource, RelativeSource={RelativeSource AncestorType=UserControl}}" Stretch="UniformToFill" ClipToBounds="True"/>
28 <!-- Two images for cross-fade -->
29 <Grid>
30 <Image x:Name="ImageBack" Stretch="UniformToFill" Opacity="0" ClipToBounds="True"/>
31 <Image x:Name="ImageFront" Stretch="UniformToFill" Opacity="1" ClipToBounds="True"/>
32 </Grid>
29 33
30 34 <!-- Bottom acrylic bar inside center card -->
31 35 <Border VerticalAlignment="Bottom" Margin="8" CornerRadius="8" Background="#CCFFFFFF" Height="64" Padding="12">
@@ -47,21 +51,39 @@
47 51 <ItemsControl.ItemTemplate>
48 52 <DataTemplate>
49 53 <Border Background="Transparent" Padding="6" Cursor="Hand" MouseLeftButtonUp="Indicator_MouseLeftButtonUp">
50 <Ellipse Width="10" Height="10" Fill="#888" Opacity="0.5">
51 <Ellipse.Style>
52 <Style TargetType="Ellipse">
53 <Style.Triggers>
54 <DataTrigger Binding="{Binding IsSelected}" Value="True">
55 <Setter Property="Fill" Value="#6A5ACD"/>
56 <Setter Property="Opacity" Value="1"/>
57 <Setter Property="Width" Value="14"/>
58 <Setter Property="Height" Value="14"/>
59 </DataTrigger>
60 </Style.Triggers>
61 </Style>
62 </Ellipse.Style>
54 <Ellipse x:Name="Dot" Width="10" Height="10" Opacity="0.5" RenderTransformOrigin="0.5,0.5">
55 <Ellipse.Fill>
56 <SolidColorBrush Color="#888888"/>
57 </Ellipse.Fill>
58 <Ellipse.RenderTransform>
59 <ScaleTransform ScaleX="1" ScaleY="1"/>
60 </Ellipse.RenderTransform>
63 61 </Ellipse>
64 62 </Border>
63 <DataTemplate.Triggers>
64 <DataTrigger Binding="{Binding IsSelected}" Value="True">
65 <DataTrigger.EnterActions>
66 <BeginStoryboard Name="EnterDot">
67 <Storyboard>
68 <ColorAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="#FF6A5ACD" Duration="0:0:0.12"/>
69 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:0.12"/>
70 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)" To="1.4" Duration="0:0:0.18"/>
71 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" To="1.4" Duration="0:0:0.18"/>
72 </Storyboard>
73 </BeginStoryboard>
74 </DataTrigger.EnterActions>
75 <DataTrigger.ExitActions>
76 <BeginStoryboard Name="ExitDot">
77 <Storyboard>
78 <ColorAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" To="#888888" Duration="0:0:0.12"/>
79 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="Opacity" To="0.5" Duration="0:0:0.12"/>
80 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleX)" To="1" Duration="0:0:0.18"/>
81 <DoubleAnimation Storyboard.TargetName="Dot" Storyboard.TargetProperty="RenderTransform.(ScaleTransform.ScaleY)" To="1" Duration="0:0:0.18"/>
82 </Storyboard>
83 </BeginStoryboard>
84 </DataTrigger.ExitActions>
85 </DataTrigger>
86 </DataTemplate.Triggers>
65 87 </DataTemplate>
66 88 </ItemsControl.ItemTemplate>
67 89 </ItemsControl>
Modified XFEToolBox/Views/Controls/Carousel.xaml.cs +57 -3
@@ -4,6 +4,8 @@ using System.Windows;
4 4 using System.Windows.Controls;
5 5 using System.Windows.Input;
6 6 using System.Windows.Media;
7 using System.Windows.Media.Animation;
8 using System.Windows.Media.Imaging;
7 9
8 10 namespace XFEToolBox.Views.Controls;
9 11
@@ -95,6 +97,9 @@ public partial class Carousel : UserControl, INotifyPropertyChanged
95 97 DataContext = this;
96 98 }
97 99
100 private Image ImageFrontControl => (Image)FindName("ImageFront");
101 private Image ImageBackControl => (Image)FindName("ImageBack");
102
98 103 private void Carousel_Loaded(object sender, RoutedEventArgs e)
99 104 {
100 105 if (timer == null)
@@ -106,7 +111,7 @@ public partial class Carousel : UserControl, INotifyPropertyChanged
106 111 timer.Tick += Timer_Tick;
107 112 }
108 113 timer.Start();
109 UpdateImage();
114 UpdateImage(true);
110 115 }
111 116
112 117 private void Carousel_Unloaded(object sender, RoutedEventArgs e)
@@ -123,7 +128,7 @@ public partial class Carousel : UserControl, INotifyPropertyChanged
123 128 }
124 129 }
125 130
126 private void UpdateImage()
131 private void UpdateImage(bool initial = false)
127 132 {
128 133 if (ImageList == null || ImageList.Count == 0)
129 134 {
@@ -143,6 +148,50 @@ public partial class Carousel : UserControl, INotifyPropertyChanged
143 148 var item = ImageList[currentIndex];
144 149 CurrentImageSource = item?.Image;
145 150 CurrentTitle = item?.Title ?? string.Empty;
151
152 // Cross-fade using named image controls
153 try
154 {
155 var front = ImageFrontControl;
156 var back = ImageBackControl;
157
158 if (front == null || back == null)
159 return;
160
161 // move front to back
162 if (front.Source != null)
163 {
164 back.Source = front.Source;
165 back.Opacity = 1;
166 }
167 else
168 {
169 back.Source = null;
170 back.Opacity = 0;
171 }
172
173 // set front to new image
174 front.Source = item?.Image;
175
176 if (initial)
177 {
178 front.Opacity = 1;
179 back.Opacity = 0;
180 }
181 else
182 {
183 var fadeOut = new DoubleAnimation(1, 0, new Duration(TimeSpan.FromMilliseconds(500))) { EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } };
184 var fadeIn = new DoubleAnimation(0, 1, new Duration(TimeSpan.FromMilliseconds(500))) { EasingFunction = new QuadraticEase { EasingMode = EasingMode.EaseOut } };
185
186 back.BeginAnimation(UIElement.OpacityProperty, fadeOut);
187 front.BeginAnimation(UIElement.OpacityProperty, fadeIn);
188 }
189 }
190 catch
191 {
192 // ignore animation errors in design time
193 }
194
146 195 OnPropertyChanged(nameof(CurrentImageSource));
147 196 OnPropertyChanged(nameof(CurrentTitle));
148 197 }
@@ -177,11 +226,16 @@ public partial class Carousel : UserControl, INotifyPropertyChanged
177 226 // Public API helpers
178 227 public void AddItem(ImageSource image, string title)
179 228 {
229 var frozen = image as BitmapSource;
230 if (frozen != null && frozen.CanFreeze)
231 {
232 try { frozen.Freeze(); } catch { }
233 }
180 234 ImageList.Add(new CarouselImageItem { Image = image, Title = title });
181 235 if (ImageList.Count == 1)
182 236 {
183 237 currentIndex = 0;
184 UpdateImage();
238 UpdateImage(true);
185 239 }
186 240 }
187 241
Modified XFEToolBox/Views/Pages/MainPage.xaml +1 -1
@@ -7,7 +7,7 @@
7 7 xmlns:local="clr-namespace:XFEToolBox.Views.Pages"
8 8 mc:Ignorable="d"
9 9 d:DesignHeight="450" d:DesignWidth="800"
10 Title="MainPage" Loaded="Page_Loaded">
10 Title="MainPage">
11 11 <Grid>
12 12 <ctr:SmoothScrollViewer>
13 13 <ScrollViewer.Resources>
Modified XFEToolBox/Views/Pages/MainPage.xaml.cs +3 -39
@@ -1,5 +1,6 @@
1 1 using System.Windows.Controls;
2 2 using System.Windows.Media;
3 using XFEToolBox.ViewModel.Pages;
3 4 using XFEToolBox.Views.Controls;
4 5
5 6 namespace XFEToolBox.Views.Pages;
@@ -10,48 +11,11 @@ namespace XFEToolBox.Views.Pages;
10 11 public partial class MainPage : Page
11 12 {
12 13 public static MainPage? Current { get; set; } = new();
14 public MainPageViewModel ViewModel { get; set; }
13 15 public MainPage()
14 16 {
15 17 Current = this;
18 ViewModel = new(this);
16 19 InitializeComponent();
17 20 }
18
19 private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e)
20 {
21 var carousel = this.FindName("mainCarousel") as Carousel;
22 if (carousel != null)
23 {
24 carousel.ImageList.Clear();
25 for (int i = 1; i <= 4; i++)
26 {
27 var img = CreatePlaceholderImage($"示例 {i}", 800, 450);
28 carousel.AddItem(img, $"示例 {i}");
29 }
30 }
31 }
32
33 private ImageSource CreatePlaceholderImage(string text, int width, int height)
34 {
35 var dv = new System.Windows.Media.DrawingVisual();
36 using (var dc = dv.RenderOpen())
37 {
38 // Background
39 var brush = new System.Windows.Media.LinearGradientBrush(System.Windows.Media.Color.FromRgb(245, 245, 250), System.Windows.Media.Color.FromRgb(220, 220, 255), 45);
40 dc.DrawRectangle(brush, null, new System.Windows.Rect(0, 0, width, height));
41
42 // Centered text
43 var formatted = new System.Windows.Media.FormattedText(text,
44 System.Globalization.CultureInfo.CurrentCulture,
45 System.Windows.FlowDirection.LeftToRight,
46 new System.Windows.Media.Typeface("Segoe UI"), 48, System.Windows.Media.Brushes.Gray, 1.0);
47
48 var pt = new System.Windows.Point((width - formatted.Width) / 2, (height - formatted.Height) / 2);
49 dc.DrawText(formatted, pt);
50 }
51
52 var bmp = new System.Windows.Media.Imaging.RenderTargetBitmap(width, height, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
53 bmp.Render(dv);
54 bmp.Freeze();
55 return bmp;
56 }
57 21 }
Modified XFEToolBox/XFEToolBox.csproj +5 -5
@@ -42,13 +42,13 @@
42 42 </ItemGroup>
43 43
44 44 <ItemGroup>
45 <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
46 <PackageReference Include="XFEExtension.NetCore" Version="3.0.2" />
47 <PackageReference Include="XFEExtension.NetCore.AutoConfig" Version="1.1.1" />
45 <PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
46 <PackageReference Include="XFEExtension.NetCore" Version="3.3.10" />
47 <PackageReference Include="XFEExtension.NetCore.AutoConfig" Version="2.0.7" />
48 48 <PackageReference Include="XFEExtension.NetCore.AutoPath" Version="1.0.1" />
49 <PackageReference Include="XFEExtension.NetCore.InputSimulator" Version="2.2.0" />
49 <PackageReference Include="XFEExtension.NetCore.InputSimulator" Version="2.3.0" />
50 50 <PackageReference Include="XFEExtension.NetCore.TodoHighLight" Version="1.0.0" />
51 <PackageReference Include="XFEExtension.NetCore.XFEConsole" Version="1.0.2" />
51 <PackageReference Include="XFEExtension.NetCore.XFEConsole" Version="1.2.3" />
52 52 </ItemGroup>
53 53
54 54 <ItemGroup>