返回提交历史
Modified
XFEToolBox/Views/Controls/Carousel.xaml
+13
-2
Modified
XFEToolBox/Views/Controls/Carousel.xaml.cs
+97
-15
Modified
XFEToolBox/Views/Pages/MainPage.xaml
+13
-16
Modified
XFEToolBox/Views/Pages/MainPage.xaml.cs
+38
-2
Modified
XFEToolBox/XFEToolBox.csproj
+1
-1
XFEstudio/XFEToolBox
初步完善轮播图
e36bd2e
代码差异
5 个文件
+162
-36
@@ -5,7 +5,7 @@
5
5
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
6
6
xmlns:local="clr-namespace:XFEToolBox.Views.Controls"
7
7
mc:Ignorable="d"
8
d:DesignHeight="450" d:DesignWidth="800">
8
d:DesignHeight="250" d:DesignWidth="600">
9
9
<Grid>
10
10
<Grid.ColumnDefinitions>
11
11
<ColumnDefinition Width="50"/>
@@ -16,6 +16,17 @@
16
16
<RowDefinition Height="*"/>
17
17
<RowDefinition Height="30"/>
18
18
</Grid.RowDefinitions>
19
<Image Source="{Binding }"/>
19
20
<!-- Main image -->
21
<Border Grid.Column="1" Grid.Row="0" CornerRadius="8" Background="LightGray" ClipToBounds="True" Margin="5">
22
<Image Stretch="UniformToFill" Source="{Binding CurrentImageSource, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
23
</Border>
24
25
<!-- Prev/Next buttons -->
26
<Button Grid.Column="0" Grid.Row="0" Width="36" Height="36" VerticalAlignment="Center" HorizontalAlignment="Center" Click="PrevButton_Click">◀</Button>
27
<Button Grid.Column="2" Grid.Row="0" Width="36" Height="36" VerticalAlignment="Center" HorizontalAlignment="Center" Click="NextButton_Click">▶</Button>
28
29
<!-- Simple position text -->
30
<TextBlock Grid.Row="1" Grid.ColumnSpan="3" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Gray" FontSize="12" Text="{Binding Path=PositionText, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
20
31
</Grid>
21
32
</UserControl>
@@ -1,4 +1,6 @@
1
using System.Windows;
1
using System.Collections.ObjectModel;
2
using System.ComponentModel;
3
using System.Windows;
2
4
using System.Windows.Controls;
3
5
using System.Windows.Media;
4
6
@@ -7,12 +9,42 @@ namespace XFEToolBox.Views.Controls;
7
9
/// <summary>
8
10
/// Carousel.xaml 的交互逻辑
9
11
/// </summary>
10
public partial class Carousel : UserControl
12
public partial class Carousel : UserControl, INotifyPropertyChanged
11
13
{
12
private int currentIndex = 0;
14
private int currentIndex = -1;
13
15
private bool isMouseOn = false;
16
private System.Windows.Threading.DispatcherTimer? timer;
17
14
18
#region DependencyProperty
15
public List<ImageSource> ImageList { get; set; } = [];
19
public ObservableCollection<ImageSource> ImageList
20
{
21
get { return (ObservableCollection<ImageSource>)GetValue(ImageListProperty); }
22
set { SetValue(ImageListProperty, value); }
23
}
24
25
public static readonly DependencyProperty ImageListProperty = DependencyProperty.Register(
26
"ImageList", typeof(ObservableCollection<ImageSource>), typeof(Carousel), new PropertyMetadata(new ObservableCollection<ImageSource>(), OnImageListChanged));
27
28
private static void OnImageListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
29
{
30
if (d is Carousel c)
31
{
32
if (e.OldValue is ObservableCollection<ImageSource> old)
33
old.CollectionChanged -= c.ImageList_CollectionChanged;
34
if (e.NewValue is ObservableCollection<ImageSource> neu)
35
neu.CollectionChanged += c.ImageList_CollectionChanged;
36
37
c.currentIndex = -1;
38
c.UpdateImage();
39
}
40
}
41
42
private void ImageList_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
43
{
44
if (currentIndex >= ImageList.Count)
45
currentIndex = ImageList.Count - 1;
46
UpdateImage();
47
}
16
48
17
49
public ImageSource CurrentImageSource
18
50
{
@@ -21,38 +53,88 @@ public partial class Carousel : UserControl
21
53
}
22
54
public static readonly DependencyProperty CurrentImageSourceProperty = DependencyProperty.Register("CurrentImageSource", typeof(ImageSource), typeof(Carousel), new PropertyMetadata(null));
23
55
24
public ImageSource AfterImageSource
56
public string PositionText
25
57
{
26
get { return (ImageSource)GetValue(AfterImageSourceProperty); }
27
set { SetValue(AfterImageSourceProperty, value); }
58
get { return (string)GetValue(PositionTextProperty); }
59
private set { SetValue(PositionTextProperty, value); }
28
60
}
29
public static readonly DependencyProperty AfterImageSourceProperty = DependencyProperty.Register("AfterImageSource", typeof(ImageSource), typeof(Carousel), new PropertyMetadata(null));
61
public static readonly DependencyProperty PositionTextProperty = DependencyProperty.Register("PositionText", typeof(string), typeof(Carousel), new PropertyMetadata(string.Empty));
30
62
#endregion
63
31
64
public Carousel()
32
65
{
66
InitializeComponent();
67
33
68
Loaded += Carousel_Loaded;
69
Unloaded += Carousel_Unloaded;
70
34
71
MouseEnter += (s, e) => isMouseOn = true;
35
72
MouseLeave += (s, e) => isMouseOn = false;
36
73
MouseMove += (s, e) => isMouseOn = true;
37
InitializeComponent();
74
75
DataContext = this;
38
76
}
39
77
40
78
private void Carousel_Loaded(object sender, RoutedEventArgs e)
41
79
{
42
var timer = new System.Windows.Threading.DispatcherTimer
80
if (timer == null)
43
81
{
44
Interval = TimeSpan.FromSeconds(3)
45
};
46
timer.Tick += Timer_Tick;
82
timer = new System.Windows.Threading.DispatcherTimer
83
{
84
Interval = TimeSpan.FromSeconds(3)
85
};
86
timer.Tick += Timer_Tick;
87
}
47
88
timer.Start();
89
UpdateImage();
90
}
91
92
private void Carousel_Unloaded(object sender, RoutedEventArgs e)
93
{
94
timer?.Stop();
48
95
}
49
96
50
97
private void Timer_Tick(object? sender, EventArgs e)
51
98
{
52
if (!isMouseOn && ImageList.Count > 0)
99
if (!isMouseOn && ImageList != null && ImageList.Count > 0)
53
100
{
54
101
currentIndex = (currentIndex + 1) % ImageList.Count;
55
CurrentImageSource = ImageList[currentIndex];
102
UpdateImage();
103
}
104
}
105
106
private void UpdateImage()
107
{
108
if (ImageList == null || ImageList.Count == 0)
109
{
110
CurrentImageSource = null;
111
PositionText = string.Empty;
112
return;
56
113
}
114
115
if (currentIndex < 0)
116
currentIndex = 0;
117
118
CurrentImageSource = ImageList[currentIndex];
119
PositionText = $"{currentIndex + 1}/{ImageList.Count}";
120
OnPropertyChanged(nameof(CurrentImageSource));
121
OnPropertyChanged(nameof(PositionText));
122
}
123
124
private void PrevButton_Click(object sender, RoutedEventArgs e)
125
{
126
if (ImageList == null || ImageList.Count == 0) return;
127
currentIndex = (currentIndex - 1 + ImageList.Count) % ImageList.Count;
128
UpdateImage();
57
129
}
130
131
private void NextButton_Click(object sender, RoutedEventArgs e)
132
{
133
if (ImageList == null || ImageList.Count == 0) return;
134
currentIndex = (currentIndex + 1) % ImageList.Count;
135
UpdateImage();
136
}
137
138
public event PropertyChangedEventHandler? PropertyChanged;
139
protected void OnPropertyChanged(string name) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
58
140
}
@@ -9,21 +9,18 @@
9
9
d:DesignHeight="450" d:DesignWidth="800"
10
10
Title="MainPage" Loaded="Page_Loaded">
11
11
<Grid>
12
<Grid.ColumnDefinitions>
13
<ColumnDefinition Width="2*"/>
14
<ColumnDefinition Width="*"/>
15
</Grid.ColumnDefinitions>
16
<Grid.RowDefinitions>
17
<RowDefinition Height="Auto"/>
18
<RowDefinition Height="2*"/>
19
<RowDefinition Height="*"/>
20
</Grid.RowDefinitions>
21
<TextBlock Margin="10,0" Text="最近使用" Foreground="{DynamicResource BackgroundColor}" FontSize="15" FontWeight="Bold"/>
22
<Border Grid.Row="1" Grid.ColumnSpan="2" CornerRadius="15" Background="White" Margin="10">
23
<ScrollViewer VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Disabled" Padding="5">
24
<WrapPanel>
25
</WrapPanel>
26
</ScrollViewer>
27
</Border>
12
<ctr:SmoothScrollViewer>
13
<ScrollViewer.Resources>
14
<Style TargetType="ScrollBar" BasedOn="{StaticResource ConsoleScrollBar}"/>
15
</ScrollViewer.Resources>
16
<StackPanel Orientation="Vertical">
17
<ctr:Carousel x:Name="mainCarousel" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="220"/>
18
<TextBlock Margin="10,0" Text="最近使用" Foreground="{DynamicResource BackgroundColor}" FontSize="15" FontWeight="Bold"/>
19
<Border CornerRadius="15" Background="White" Margin="10" Padding="10">
20
<WrapPanel MinHeight="500">
21
</WrapPanel>
22
</Border>
23
</StackPanel>
24
</ctr:SmoothScrollViewer>
28
25
</Grid>
29
26
</Page>
@@ -1,6 +1,7 @@
1
1
using System.Windows.Controls;
2
using XFEExtension.NetCore.FileExtension;
3
using XFEToolBox.Utilities;
2
using System.Windows.Media;
3
using System.Windows.Media.Imaging;
4
using XFEToolBox.Views.Controls;
4
5
5
6
namespace XFEToolBox.Views.Pages;
6
7
@@ -18,5 +19,40 @@ public partial class MainPage : Page
18
19
19
20
private void Page_Loaded(object sender, System.Windows.RoutedEventArgs e)
20
21
{
22
var carousel = this.FindName("mainCarousel") as Carousel;
23
if (carousel != null)
24
{
25
carousel.ImageList.Clear();
26
for (int i = 1; i <= 4; i++)
27
{
28
var img = CreatePlaceholderImage($"示例 {i}", 800, 450);
29
carousel.ImageList.Add(img);
30
}
31
}
32
}
33
34
private ImageSource CreatePlaceholderImage(string text, int width, int height)
35
{
36
var dv = new DrawingVisual();
37
using (var dc = dv.RenderOpen())
38
{
39
// Background
40
var brush = new LinearGradientBrush(Color.FromRgb(240, 240, 240), Color.FromRgb(200, 200, 255), 45);
41
dc.DrawRectangle(brush, null, new System.Windows.Rect(0, 0, width, height));
42
43
// Centered text
44
var formatted = new FormattedText(text,
45
System.Globalization.CultureInfo.CurrentCulture,
46
System.Windows.FlowDirection.LeftToRight,
47
new Typeface("Segoe UI"), 48, Brushes.Gray, 1.0);
48
49
var pt = new System.Windows.Point((width - formatted.Width) / 2, (height - formatted.Height) / 2);
50
dc.DrawText(formatted, pt);
51
}
52
53
var bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
54
bmp.Render(dv);
55
bmp.Freeze();
56
return bmp;
21
57
}
22
58
}
@@ -2,7 +2,7 @@
2
2
3
3
<PropertyGroup>
4
4
<OutputType>WinExe</OutputType>
5
<TargetFramework>net9.0-windows</TargetFramework>
5
<TargetFramework>net10.0-windows</TargetFramework>
6
6
<Nullable>enable</Nullable>
7
7
<ImplicitUsings>enable</ImplicitUsings>
8
8
<UseWPF>true</UseWPF>