WPF之Slider控件详解

文章目录

    • 1. 概述
    • 2. 基本属性
      • 2.1 值范围属性
      • 2.2 滑动步长属性
      • 2.3 刻度显示属性
      • 2.4 方向属性
      • 2.5 选择范围属性
    • 3. 事件处理
      • 3.1 值变化事件
      • 3.2 滑块拖动事件
    • 4. 样式和模板自定义
      • 4.1 基本样式设置
      • 4.2 控件模板自定义
    • 5. 数据绑定
      • 5.1 绑定到ViewModel
      • 5.2 同步多个控件
    • 6. 实际应用示例
      • 6.1 音量控制器
      • 6.2 颜色选择器
    • 7. 范围滑块(RangeSlider)实现
      • 7.1 基本实现思路
      • 7.2 RangeSlider控件实现示例
      • 7.3 RangeSlider控件的使用
    • 8. 高级应用:可视化数据滑块
    • 9. 注意事项和最佳实践
      • 9.1 性能考虑
      • 9.2 可访问性考虑
      • 9.3 响应式设计
    • 10. 总结
    • 11. 相关资源

可以根据Github拉取示例程序运行
GitHub程序演示地址(点击直达)
也可以在本文资源中下载
在这里插入图片描述


1. 概述

Slider(滑块)控件是WPF中常用的一种范围控件,继承自RangeBase抽象类。它允许用户通过拖动滑块在一个指定的数值范围内选择一个值。Slider控件广泛应用于音量调节、亮度控制、进度显示等场景,为用户提供了直观的交互方式。

2. 基本属性

2.1 值范围属性

Slider控件的核心属性是其值范围,包括以下几个重要属性:

// 设置滑块的最小值,默认为0
slider.Minimum = 0;// 设置滑块的最大值,默认为10
slider.Maximum = 100;// 当前滑块的值
slider.Value = 50;

这些属性都是双精度浮点数(double)类型,可以通过XAML或代码设置:

<Slider Minimum="0" Maximum="100" Value="50" Width="200"/>

2.2 滑动步长属性

Slider控件提供了几个控制步长的属性,用于定义滑块移动的精度:

<!-- 定义每次鼠标单击或按键操作时滑块移动的小增量值 -->
<Slider SmallChange="1" <!-- 定义按Page Up/Page Down键时滑块移动的大增量值 -->LargeChange="10" <!-- 设置刻度频率,每5个单位显示一个刻度 -->TickFrequency="5" Minimum="0" Maximum="100"Width="300"/>

在代码中可以这样设置:

// 设置小步长值
slider.SmallChange = 1;// 设置大步长值
slider.LargeChange = 10;// 设置刻度频率
slider.TickFrequency = 5;

2.3 刻度显示属性

Slider控件可以显示刻度标记,用于指示值的位置:

<Slider TickPlacement="BottomRight" IsSnapToTickEnabled="True"TickFrequency="10"Minimum="0" Maximum="100"Width="300"/>

TickPlacement属性用于指定刻度线的位置,可选值包括:

  • None:不显示刻度线(默认值)
  • TopLeft:刻度线显示在上方(水平方向)或左侧(垂直方向)
  • BottomRight:刻度线显示在下方(水平方向)或右侧(垂直方向)
  • Both:刻度线同时显示在两侧

IsSnapToTickEnabled属性指定滑块是否自动吸附到最近的刻度位置,当设置为True时,用户释放滑块后,滑块会自动移动到最近的刻度位置。

除了TickFrequency属性设置等间距的刻度外,还可以使用Ticks属性设置不规则的刻度位置:

<Slider Minimum="0" Maximum="100" Width="300"><Slider.Ticks><x:Double>0</x:Double><x:Double>10</x:Double><x:Double>25</x:Double><x:Double>50</x:Double><x:Double>75</x:Double><x:Double>100</x:Double></Slider.Ticks>
</Slider>

2.4 方向属性

Slider控件可以水平或垂直放置,通过Orientation属性控制:

<!-- 水平滑块(默认) -->
<Slider Orientation="Horizontal" Width="200"/><!-- 垂直滑块 -->
<Slider Orientation="Vertical" Height="200"/>

2.5 选择范围属性

Slider控件允许高亮显示一个范围区域:

<Slider Minimum="0" Maximum="100" Value="75"IsSelectionRangeEnabled="True"SelectionStart="25"SelectionEnd="75"Width="300"/>
  • IsSelectionRangeEnabled:是否启用选择范围
  • SelectionStart:选择范围的起始值
  • SelectionEnd:选择范围的结束值

IsSelectionRangeEnabled设置为True时,滑块会在指定范围内显示一个不同颜色的区域。

3. 事件处理

Slider控件提供了多个事件用于响应用户交互:

3.1 值变化事件

最常用的事件是ValueChanged,当滑块的值发生变化时触发:

<Slider ValueChanged="Slider_ValueChanged" Minimum="0" Maximum="100"Width="300"/>

对应的事件处理代码:

private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{// 获取旧值double oldValue = e.OldValue;// 获取新值double newValue = e.NewValue;// 处理值变化valueTextBlock.Text = $"当前值: {newValue:F1}";
}

3.2 滑块拖动事件

滑块的拖动操作可以通过Thumb控件的事件来捕获:

// 获取滑块内部的Thumb控件
Track track = slider.Template.FindName("PART_Track", slider) as Track;
Thumb thumb = track?.Thumb;if (thumb != null)
{// 注册拖动开始事件thumb.DragStarted += Thumb_DragStarted;// 注册拖动进行中事件thumb.DragDelta += Thumb_DragDelta;// 注册拖动结束事件thumb.DragCompleted += Thumb_DragCompleted;
}

事件处理代码示例:

private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
{// 拖动开始时的处理statusTextBlock.Text = "开始拖动";
}private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{// 拖动过程中的处理Slider slider = (sender as Thumb)?.TemplatedParent as Slider;if (slider != null){statusTextBlock.Text = $"正在拖动: {slider.Value:F1}";}
}private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
{// 拖动结束时的处理statusTextBlock.Text = "拖动结束";
}

4. 样式和模板自定义

4.1 基本样式设置

可以通过设置Style来自定义Slider的外观:

<Slider Width="300" Margin="10"><Slider.Style><Style TargetType="Slider"><Setter Property="Background" Value="LightGray"/><Setter Property="Foreground" Value="Blue"/><Setter Property="BorderBrush" Value="Gray"/><Setter Property="BorderThickness" Value="1"/></Style></Slider.Style>
</Slider>

4.2 控件模板自定义

要完全控制Slider的外观,可以通过重写ControlTemplate来实现:

<Slider Width="300" Margin="10"><Slider.Template><ControlTemplate TargetType="Slider"><Grid><Border x:Name="TrackBackground" Height="4" Background="#E0E0E0" CornerRadius="2"/><Border x:Name="PART_SelectionRange" Height="4" Background="#2196F3" HorizontalAlignment="Left" CornerRadius="2"/><Track x:Name="PART_Track"><Track.Thumb><Thumb Width="20" Height="20"><Thumb.Template><ControlTemplate TargetType="Thumb"><Ellipse Fill="#2196F3" Stroke="#1565C0" StrokeThickness="1"/></ControlTemplate></Thumb.Template></Thumb></Track.Thumb></Track></Grid><ControlTemplate.Triggers><Trigger Property="IsSelectionRangeEnabled" Value="True"><Setter TargetName="PART_SelectionRange" Property="Visibility" Value="Visible"/></Trigger><Trigger Property="IsSelectionRangeEnabled" Value="False"><Setter TargetName="PART_SelectionRange" Property="Visibility" Value="Collapsed"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Slider.Template>
</Slider>

注意:自定义模板时,必须保留名为PART_TrackPART_SelectionRange的元素,这些是Slider控件正常工作所必需的部分。

5. 数据绑定

5.1 绑定到ViewModel

Slider控件可以轻松地通过数据绑定与ViewModel集成:

<Slider Minimum="0" Maximum="100" Value="{Binding SliderValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"Width="300"/><TextBlock Text="{Binding SliderValue, StringFormat='当前值: {0:F1}'}" Margin="10"/>

对应的ViewModel代码:

public class MainViewModel : INotifyPropertyChanged
{private double _sliderValue;public double SliderValue{get => _sliderValue;set{if (_sliderValue != value){_sliderValue = value;OnPropertyChanged(nameof(SliderValue));}}}public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}

5.2 同步多个控件

可以使用数据绑定使多个控件同步显示相同的值:

<Slider x:Name="mainSlider" Minimum="0" Maximum="100" Value="{Binding Volume, Mode=TwoWay}"Width="300"/><ProgressBar Value="{Binding ElementName=mainSlider, Path=Value}" Maximum="{Binding ElementName=mainSlider, Path=Maximum}"Height="10" Width="300" Margin="0,10"/><TextBlock Text="{Binding ElementName=mainSlider, Path=Value, StringFormat='音量: {0:F0}%'}" Margin="10"/>

6. 实际应用示例

6.1 音量控制器

下面是一个简单的音量控制器实现:

<StackPanel Margin="20"><TextBlock Text="音量控制" FontWeight="Bold" Margin="0,0,0,10"/><!-- 音量图标 --><StackPanel Orientation="Horizontal" Margin="0,0,0,5"><Path Data="M0,5 L3,5 L7,1 L7,9 L3,5 Z" Fill="Black" Margin="0,0,5,0"/><!-- 音量滑块 --><Slider x:Name="volumeSlider" Minimum="0" Maximum="100" Value="50" Width="200"ValueChanged="VolumeSlider_ValueChanged"/><!-- 当前值显示 --><TextBlock Text="{Binding ElementName=volumeSlider, Path=Value, StringFormat='{0:F0}%'}" Width="40" VerticalAlignment="Center" Margin="5,0,0,0"/></StackPanel><!-- 静音切换 --><CheckBox x:Name="muteCheckBox" Content="静音" Checked="MuteCheckBox_Checked" Unchecked="MuteCheckBox_Unchecked"/>
</StackPanel>
private double previousVolume = 50;private void VolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{// 这里可以调用系统API或媒体播放器的音量调节方法if (!muteCheckBox.IsChecked.Value){previousVolume = volumeSlider.Value;}
}private void MuteCheckBox_Checked(object sender, RoutedEventArgs e)
{// 保存当前音量并设置为0previousVolume = volumeSlider.Value;volumeSlider.Value = 0;
}private void MuteCheckBox_Unchecked(object sender, RoutedEventArgs e)
{// 恢复之前的音量volumeSlider.Value = previousVolume;
}

6.2 颜色选择器

使用多个Slider控制RGB颜色值:

<StackPanel Margin="20"><TextBlock Text="颜色选择器" FontWeight="Bold" Margin="0,0,0,10"/><!-- 红色滑块 --><StackPanel Orientation="Horizontal" Margin="0,5"><TextBlock Text="R:" Width="20"/><Slider x:Name="redSlider" Minimum="0" Maximum="255" Value="120" Width="200"ValueChanged="ColorSlider_ValueChanged"/><TextBlock Text="{Binding ElementName=redSlider, Path=Value, StringFormat='{0:F0}'}" Width="30" Margin="5,0,0,0"/></StackPanel><!-- 绿色滑块 --><StackPanel Orientation="Horizontal" Margin="0,5"><TextBlock Text="G:" Width="20"/><Slider x:Name="greenSlider" Minimum="0" Maximum="255" Value="180" Width="200"ValueChanged="ColorSlider_ValueChanged"/><TextBlock Text="{Binding ElementName=greenSlider, Path=Value, StringFormat='{0:F0}'}" Width="30" Margin="5,0,0,0"/></StackPanel><!-- 蓝色滑块 --><StackPanel Orientation="Horizontal" Margin="0,5"><TextBlock Text="B:" Width="20"/><Slider x:Name="blueSlider" Minimum="0" Maximum="255" Value="240" Width="200"ValueChanged="ColorSlider_ValueChanged"/><TextBlock Text="{Binding ElementName=blueSlider, Path=Value, StringFormat='{0:F0}'}" Width="30" Margin="5,0,0,0"/></StackPanel><!-- 颜色预览 --><Border x:Name="colorPreview" Height="50" Margin="0,10,0,0" BorderBrush="Black" BorderThickness="1"/><!-- 16进制颜色值 --><TextBlock x:Name="hexColorTextBlock" HorizontalAlignment="Center" Margin="0,5,0,0" FontFamily="Consolas"/>
</StackPanel>
private void ColorSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{// 创建色彩对象Color color = Color.FromRgb((byte)redSlider.Value,(byte)greenSlider.Value,(byte)blueSlider.Value);// 更新预览colorPreview.Background = new SolidColorBrush(color);// 更新16进制值显示hexColorTextBlock.Text = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
}

7. 范围滑块(RangeSlider)实现

WPF默认没有提供范围滑块控件,但我们可以通过自定义控件实现一个具有两个滑块的范围选择器。

7.1 基本实现思路

实现一个RangeSlider控件的基本思路是:

  1. 创建一个继承自Control的自定义控件
  2. 添加两个表示范围起始和结束的DependencyProperty
  3. 使用两个Thumb控件分别控制这两个值
  4. 通过XAML模板定义控件的外观

7.2 RangeSlider控件实现示例

以下是一个简化的RangeSlider实现:

// RangeSlider.cs
public class RangeSlider : Control
{static RangeSlider(){DefaultStyleKeyProperty.OverrideMetadata(typeof(RangeSlider), new FrameworkPropertyMetadata(typeof(RangeSlider)));}#region 依赖属性定义public static readonly DependencyProperty MinimumProperty =DependencyProperty.Register("Minimum", typeof(double), typeof(RangeSlider),new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsRender));public static readonly DependencyProperty MaximumProperty =DependencyProperty.Register("Maximum", typeof(double), typeof(RangeSlider),new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsRender));public static readonly DependencyProperty LowerValueProperty =DependencyProperty.Register("LowerValue", typeof(double), typeof(RangeSlider),new FrameworkPropertyMetadata(20.0, FrameworkPropertyMetadataOptions.AffectsRender));public static readonly DependencyProperty UpperValueProperty =DependencyProperty.Register("UpperValue", typeof(double), typeof(RangeSlider),new FrameworkPropertyMetadata(80.0, FrameworkPropertyMetadataOptions.AffectsRender));#endregion#region 属性public double Minimum{get { return (double)GetValue(MinimumProperty); }set { SetValue(MinimumProperty, value); }}public double Maximum{get { return (double)GetValue(MaximumProperty); }set { SetValue(MaximumProperty, value); }}public double LowerValue{get { return (double)GetValue(LowerValueProperty); }set { SetValue(LowerValueProperty, Math.Max(Minimum, Math.Min(UpperValue, value))); }}public double UpperValue{get { return (double)GetValue(UpperValueProperty); }set { SetValue(UpperValueProperty, Math.Min(Maximum, Math.Max(LowerValue, value))); }}#endregion#region 事件public static readonly RoutedEvent LowerValueChangedEvent =EventManager.RegisterRoutedEvent("LowerValueChanged", RoutingStrategy.Bubble,typeof(RoutedPropertyChangedEventHandler<double>), typeof(RangeSlider));public static readonly RoutedEvent UpperValueChangedEvent =EventManager.RegisterRoutedEvent("UpperValueChanged", RoutingStrategy.Bubble,typeof(RoutedPropertyChangedEventHandler<double>), typeof(RangeSlider));public event RoutedPropertyChangedEventHandler<double> LowerValueChanged{add { AddHandler(LowerValueChangedEvent, value); }remove { RemoveHandler(LowerValueChangedEvent, value); }}public event RoutedPropertyChangedEventHandler<double> UpperValueChanged{add { AddHandler(UpperValueChangedEvent, value); }remove { RemoveHandler(UpperValueChangedEvent, value); }}#endregion// 其他必要的方法和事件处理
}

控件的XAML模板(通常放在Themes/Generic.xaml中):

<Style TargetType="{x:Type local:RangeSlider}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:RangeSlider}"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="Auto"/></Grid.RowDefinitions><!-- 滑块轨道 --><Border x:Name="TrackBackground" Grid.Row="1" Height="4" Background="#E0E0E0" CornerRadius="2"Margin="10,0"/><!-- 选中范围 --><Border x:Name="SelectedRange" Grid.Row="1" Height="4" Background="#2196F3" CornerRadius="2"/><!-- 左侧滑块 --><Thumb x:Name="LowerThumb" Grid.Row="1" Width="16" Height="16"><Thumb.Template><ControlTemplate TargetType="Thumb"><Ellipse Fill="#2196F3" Stroke="#1565C0" StrokeThickness="1"/></ControlTemplate></Thumb.Template></Thumb><!-- 右侧滑块 --><Thumb x:Name="UpperThumb" Grid.Row="1" Width="16" Height="16"><Thumb.Template><ControlTemplate TargetType="Thumb"><Ellipse Fill="#2196F3" Stroke="#1565C0" StrokeThickness="1"/></ControlTemplate></Thumb.Template></Thumb></Grid></ControlTemplate></Setter.Value></Setter>
</Style>

7.3 RangeSlider控件的使用

在XAML中使用自定义的RangeSlider控件:

<local:RangeSlider Minimum="0" Maximum="100" LowerValue="20" UpperValue="80"Width="300"Margin="10"LowerValueChanged="RangeSlider_LowerValueChanged"UpperValueChanged="RangeSlider_UpperValueChanged"/><TextBlock x:Name="rangeTextBlock" Text="Range: 20 - 80" HorizontalAlignment="Center" Margin="10"/>
private void RangeSlider_LowerValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{UpdateRangeText();
}private void RangeSlider_UpperValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{UpdateRangeText();
}private void UpdateRangeText()
{var slider = sender as RangeSlider;if (slider != null){rangeTextBlock.Text = $"Range: {slider.LowerValue:F1} - {slider.UpperValue:F1}";}
}

8. 高级应用:可视化数据滑块

Slider控件可以与其他技术结合,创建更有吸引力和功能性的界面元素。下面是一个简单的可视化数据滑块示例:

<Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition Height="*"/></Grid.RowDefinitions><!-- 数据可视化 --><Canvas x:Name="visualizationCanvas" Grid.Row="0" Height="100" Background="#F5F5F5"/><!-- 滑块 --><Slider x:Name="dataSlider" Grid.Row="1" Minimum="0" Maximum="100" Value="0"ValueChanged="DataSlider_ValueChanged"/>
</Grid>
private List<double> dataPoints;public MainWindow()
{InitializeComponent();// 生成示例数据点GenerateDataPoints();// 绘制数据可视化DrawDataVisualization();
}private void GenerateDataPoints()
{dataPoints = new List<double>();Random random = new Random();for (int i = 0; i < 100; i++){dataPoints.Add(random.NextDouble() * 80 + 10); // 值在10-90之间}
}private void DrawDataVisualization()
{visualizationCanvas.Children.Clear();double width = visualizationCanvas.ActualWidth;double height = visualizationCanvas.ActualHeight;if (width <= 0 || height <= 0 || dataPoints.Count == 0)return;double segmentWidth = width / dataPoints.Count;for (int i = 0; i < dataPoints.Count; i++){double value = dataPoints[i];double barHeight = height * (value / 100);Rectangle rect = new Rectangle{Width = segmentWidth - 1,Height = barHeight,Fill = new SolidColorBrush(Color.FromRgb(33, 150, 243)),Stroke = new SolidColorBrush(Colors.White),StrokeThickness = 0.5};Canvas.SetLeft(rect, i * segmentWidth);Canvas.SetBottom(rect, 0);visualizationCanvas.Children.Add(rect);}// 绘制当前位置指示器DrawPositionIndicator();
}private void DrawPositionIndicator()
{if (dataPoints.Count == 0)return;double width = visualizationCanvas.ActualWidth;double height = visualizationCanvas.ActualHeight;int index = (int)dataSlider.Value;if (index >= dataPoints.Count)index = dataPoints.Count - 1;double segmentWidth = width / dataPoints.Count;// 绘制位置指示线Line line = new Line{X1 = index * segmentWidth + segmentWidth / 2,Y1 = 0,X2 = index * segmentWidth + segmentWidth / 2,Y2 = height,Stroke = new SolidColorBrush(Colors.Red),StrokeThickness = 2};visualizationCanvas.Children.Add(line);// 显示当前值TextBlock textBlock = new TextBlock{Text = $"{dataPoints[index]:F1}",Foreground = new SolidColorBrush(Colors.Black),Background = new SolidColorBrush(Color.FromArgb(200, 255, 255, 255)),Padding = new Thickness(3)};Canvas.SetLeft(textBlock, index * segmentWidth);Canvas.SetTop(textBlock, height - 20);visualizationCanvas.Children.Add(textBlock);
}private void DataSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{DrawDataVisualization();
}

9. 注意事项和最佳实践

9.1 性能考虑

  • 在频繁值变化的场景中,考虑节流(Throttling)或防抖(Debouncing)处理ValueChanged事件。
  • 对于大型数据可视化,考虑使用虚拟化或分页加载技术以保持良好性能。
// 使用DispatcherTimer实现简单的节流效果
private DispatcherTimer _valueChangedTimer;
private double _lastValue;public MainWindow()
{InitializeComponent();_valueChangedTimer = new DispatcherTimer{Interval = TimeSpan.FromMilliseconds(100)};_valueChangedTimer.Tick += ValueChangedTimer_Tick;
}private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{_lastValue = e.NewValue;if (!_valueChangedTimer.IsEnabled){_valueChangedTimer.Start();}
}private void ValueChangedTimer_Tick(object sender, EventArgs e)
{_valueChangedTimer.Stop();// 执行实际的更新操作UpdateUI(_lastValue);
}

9.2 可访问性考虑

为了提升应用程序的可访问性,请考虑以下几点:

  • 添加恰当的工具提示(ToolTip)以提供额外信息
  • 确保控件可以通过键盘操作
  • 考虑视觉障碍用户,使用足够的对比度和合适的大小
<Slider AutomationProperties.Name="Volume Control"AutomationProperties.HelpText="Adjust the volume from 0 to 100 percent"ToolTip="拖动调整音量"Minimum="0" Maximum="100" Width="300"><Slider.Resources><!-- 增加Thumb大小以便于点击 --><Style TargetType="Thumb"><Setter Property="Width" Value="24"/><Setter Property="Height" Value="24"/></Style></Slider.Resources>
</Slider>

9.3 响应式设计

在响应式设计中使用Slider时,可以结合其他布局控件实现良好的自适应布局:

<Grid><Grid.ColumnDefinitions><ColumnDefinition Width="Auto"/><ColumnDefinition Width="*"/><ColumnDefinition Width="Auto"/></Grid.ColumnDefinitions><!-- 最小值标签 --><TextBlock Grid.Column="0" Text="0%" VerticalAlignment="Center"/><!-- 自适应宽度的滑块 --><Slider Grid.Column="1" Minimum="0" Maximum="100" Margin="10,0"/><!-- 最大值标签 --><TextBlock Grid.Column="2" Text="100%" VerticalAlignment="Center"/>
</Grid>

10. 总结

Slider控件是WPF中一个功能强大且灵活的UI元素,适用于各种需要在特定范围内选择值的场景。通过本文介绍的基本属性、事件处理、样式自定义和高级应用,您应该能够在实际应用中充分利用Slider控件的功能。对于需要范围选择的场景,自定义RangeSlider控件提供了更加丰富的用户交互体验。

11. 相关资源

  • WPF Slider类官方文档
  • WPF数据绑定概述
  • Microsoft Learn - WPF UI设计

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/78290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

mysql索引及数据库引擎

顺序io&#xff08;不需要每次都磁盘寻址&#xff0c;效率高&#xff09;&#xff0c;随机io&#xff08;需要每次都磁盘寻址&#xff0c;效率低&#xff09; 如何正确的创建合适的索引&#xff1f; 索引是一种分散存储的数据结构 磁盘io特性&#xff1a;每次交互是以页为单位&…

网络安全:sql注入练习靶场——sqli_labs安装保姆级教程

网络安全&#xff1a;sql注入练习靶场——sqli_labs安装保姆级教程 前言 sqli-labs靶场是一个开源的sql注入练习的综合靶场&#xff0c;包含大部分sql注入漏洞以及注入方式 网络安全学习者可以通过在sqli-labs靶场练习提升对sql注入的理解&#xff0c;以及学习各种绕过姿势。…

平台介绍-开放API接口-鉴权

平台的理念是一个组织内部只建一套系统。但是现实情况是&#xff0c;组织内部已经建立了很多系统&#xff0c;是不能一次性替代的&#xff0c;只能先搭起平台&#xff0c;然后逐步开始替换。这样就不可避免的存在其他系统和平台进行交互的问题。 平台为此设计了开放API接口。其…

多端定制系统开发:打造高效全平台覆盖的APP解决方案

在移动互联网时代&#xff0c;用户需求日益多样化&#xff0c;企业若想触达更广泛的受众&#xff0c;仅靠单一平台的应用已远远不够。无论是iOS、Android、Web端&#xff0c;还是智能手表、车载设备等新兴终端&#xff0c;多端适配已成为企业数字化转型的刚需。多端定制系统开发…

Linux电源管理(5)_Hibernate和Sleep功能介绍

原文&#xff1a;Linux电源管理(5)_Hibernate和Sleep功能介绍 1. 前言 Hibernate和Sleep两个功能是Linux PM的核心功能&#xff0c;它们的目的是类似的&#xff1a;暂停使用——>保存上下文——>关闭系统以节电>恢复系统——>恢复上下文——>继续使用。 本文…

Spring 命名空间注入:p、c 与 .util 的深度解析

在 Spring 框架的开发过程中&#xff0c;XML 配置是一种常见且强大的方式来管理 Bean。为了让配置更加简洁、易读&#xff0c;Spring 提供了多种命名空间注入的方法&#xff0c;其中 p 命名空间注入、c 命名空间注入和 .util 命名空间尤为重要。本文将详细介绍这三种命名空间的…

RUST变量学习笔记

1&#xff0c;作用域概念 捕获环境 2&#xff0c;所有权概念 Rust则是通过所有权和借用来保证内存安全。很多人不理解为啥说Rust是内存安全的&#xff0c;其实就是在默认情况下&#xff0c;你是写不出内存不安全的代码的。 Rust的所有权并不难理解&#xff0c;它有且只有如下…

探索 Spring AI 的 ChatClient API:构建智能对话应用的利器

探索 Spring AI 的 ChatClient API&#xff1a;构建智能对话应用的利器 前言 在当今人工智能蓬勃发展的时代&#xff0c;智能对话系统成为了众多应用的核心组成部分。无论是客服机器人、智能助手还是聊天应用&#xff0c;都离不开高效、灵活的对话处理能力。Spring AI 作为 S…

开源ERP系统对比:Dolibarr、ERPNext与Odoo

对于寻求开源ERP解决方案的企业而言&#xff0c;Dolibarr、ERPNext和Odoo是三个备受关注的选择。它们各自拥有独特的优势和特点&#xff0c;适用于不同规模和需求的组织。以下是对这三个系统的详细介绍和对比&#xff0c;以帮助您更好地理解它们的差异&#xff0c;并结合中文支…

【2025年】MySQL面试题总结

文章目录 1. MySQL 支持哪些存储引擎&#xff1f;默认使⽤哪个&#xff1f;2. MyISAM 和 InnoDB 有什么区别&#xff1f;3. 事务的四大特性?4. 并发事务带来了哪些问题?5. 不可重复读和幻读有什么区别&#xff1f;6. MySQL 事务隔离级别&#xff1f;默认是什么级别&#xff1…

Linux常用命令29——delgroup删除组

在使用Linux或macOS日常开发中&#xff0c;熟悉一些基本的命令有助于提高工作效率&#xff0c;delgroup 是用于删除用户组的一个命令。此命令通常由超级用户&#xff08;root&#xff09;运行&#xff0c;或者通过 sudo 提权来操作。本篇学习记录delgroup命令的基本使用。 下面…

字节暑期实习-网络运维工程师面经

岗位描述 这个是ByteIntern实习&#xff0c;是暑期实习岗位 岗位 一面 先自我介绍 抓项目技术&#xff08;会进行确认是什么技术&#xff09; TCP的三次握手和四次挥手 序列号和确认应答号的位置和大小 序列号是随机的吗&#xff1f; 序列号为什么是随机的&#xff1f; …

5.3刷题

P3370 【模板】字符串哈希 #include<bits/stdc.h> using namespace std; #define int long long typedef unsigned long long ull; int n; ull myhash(string s){ull code 0, x 131, y 140814840257324663;for(int i 0; i < s.size(); i){code (code * x (ull)…

Kettle下载安装教程

## 什么是Kettle Kettle&#xff08;现在也称为Pentaho Data Integration&#xff0c;简称PDI&#xff09;是一款开源的ETL&#xff08;Extract-Transform-Load&#xff09;工具&#xff0c;用于数据抽取、转换和加载。它允许用户通过图形化界面设计和执行数据集成流程&#xf…

FreeRtos实战从入门到精通--任务创建和删除(动态方法)--事了拂衣去,深藏功与名

FreeRtos是之前的一些聪明的工程师写的免费且开源的嵌入式实时操作系统代码&#xff0c;由于我们实际工作中不需要再去写rtos&#xff0c;我们只需要用就行了&#xff0c;所以博主这里只分享项目工程实战相关的内容&#xff0c;具体rtos源码&#xff0c;可以无需理会&#xff0…

Java通用Mapper自定义方法

目录 一、定义通用 Mapper 接口二、继承通用 Mapper 实现自定义方法三、注册自定义 Mapper 接口四、在实体类对应的 Mapper 接口中使用自定义方法五、实现自定义方法的 SQL 逻辑注解方式XML 映射文件方式六、使用自定义方法七、注意事项在 Java 持久层开发中,MyBatis 的通用 M…

Android WebRTC回声消除

文章目录 安卓可用的回声消除手段各种回声消除技术优缺点WebRTC回声消除WebRTC回声消除回声消除处理流程WebRTC AECM APP 安卓可用的回声消除手段 硬件回声消除 使用 AudioRecord 的 VOICE_COMMUNICATION 模式&#xff1a;通过 AudioRecord 的 VOICE_COMMUNICATION 音频源可以…

基于 SAFM 超分辨率上采样模块的 YOLOv12 改进方法—模糊场景目标检测精度提升研究

在复杂视觉环境中,如低光照、雾天或远距离拍摄等场景下,图像质量下降导致目标模糊,使得传统目标检测模型难以实现高精度识别。YOLO系列作为主流单阶段检测框架,在速度和精度方面表现出色,但在模糊和小目标场景中仍存在性能瓶颈。本文提出一种面向 YOLOv12 的创新性改进方法…

Spring 事务的底层原理常见陷阱

一、Spring 事务的底层原理 1. 核心机制 动态代理&#xff08;AOP&#xff09;&#xff1a; Spring 通过动态代理&#xff08;JDK 或 CGLIB&#xff09;生成代理对象&#xff0c;拦截被 Transactional 注解标记的方法。事务拦截器&#xff1a; TransactionInterceptor 负责管…

Java SE(6)——类和对象(一)

1.初始面向对象 1.1 什么是面向对象 Java是一门纯面向对象的编程语言(Object Oriented Program&#xff0c;简称OOP)&#xff0c;在面向对象的世界里&#xff0c;一切皆为对象。面向对象是解决问题的一种思想&#xff0c;主要依靠对象之间的交换来完成一件事情 1.2 面向过程…