wpf 自定义控件(包含依赖属性以及事件)
wpf 事件https://blog.csdn.net/weixin_44240082/article/details/99062899
创建了这个依赖属性,就可以直接在对应的控件中使用了,就像是button中一开始就内置的width等属性一样,这个在设计自定义控件的时候用的尤其多
https://www.cnblogs.com/yang-fei/p/4724899.html 分页
下面讲的是自定义分页控件代码:
<UserControl x:Class="WPFDataGridPaging.Pager" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WPFDataGridPaging" mc:Ignorable="d" d:DesignHeight="30" d:DesignWidth="220"> <UserControl.Resources> <Style TargetType="{x:Type Button}"> <Setter Property="Width" Value="22"/> <Setter Property="Height" Value="22"/> </Style> </UserControl.Resources> <Grid> <StackPanel Orientation="Horizontal"> <Button x:Name="FirstPageButton" Margin="5,0" Click="FirstPageButton_Click"> <Path Width="7" Height="10" Data="M0,0L0,10 M0,5L6,2 6,8 0,5" Stroke="Black" StrokeThickness="1"
Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center" /> </Button> <Button x:Name="PreviousPageButton" Margin="0,0,5,0" Click="PreviousPageButton_Click"> <Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center" /> </Button> <TextBlock VerticalAlignment="Center"> <Run Text="第"/> <Run x:Name="rCurrent" Text="0"/> <Run Text="页"/> </TextBlock> <Button Margin="5,0" x:Name="NextPageButton" Click="NextPageButton_Click"> <Path Width="8" Height="8" Data="M0,4L8,0 8,8z" Stroke="Black" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"> <Path.RenderTransform> <RotateTransform Angle="180" CenterX="4" CenterY="4" /> </Path.RenderTransform> </Path> </Button> <Button Margin="0,0,5,0" x:Name="LastPageButton" Click="LastPageButton_Click"> <Path x:Name="MainPath" Width="7" Height="10" Data="M0,0L0,10 M0,5 L6,2 6,8 0,5"
Stroke="Black" StrokeThickness="1" Fill="Black" VerticalAlignment="Center" HorizontalAlignment="Center"> <Path.RenderTransform> <RotateTransform Angle="180" CenterX="3" CenterY="5" /> </Path.RenderTransform> </Path> </Button> <TextBlock VerticalAlignment="Center"> <Run Text="共"/> <Run x:Name="rTotal" Text="0"/> <Run Text="页"/> </TextBlock> </StackPanel> </Grid> </UserControl>
界面:
后台代码:
public partial class Pager : UserControl { #region 声明事件和依赖属性 public static RoutedEvent FirstPageEvent; public static RoutedEvent PreviousPageEvent; public static RoutedEvent NextPageEvent; public static RoutedEvent LastPageEvent; public static readonly DependencyProperty CurrentPageProperty; public static readonly DependencyProperty TotalPageProperty; #endregion public string CurrentPage { get { return (string)GetValue(CurrentPageProperty); } set { SetValue(CurrentPageProperty, value); } } public string TotalPage { get { return (string)GetValue(TotalPageProperty); } set { SetValue(TotalPageProperty, value); } } public Pager() { InitializeComponent(); } static Pager() { #region 注册事件以及依赖属性 //注册FirstPageEvent事件,事件的拥有者是Pager,路由事件的名称是FirstPage,这是唯一的 FirstPageEvent = EventManager.RegisterRoutedEvent("FirstPage", RoutingStrategy.Direct,
typeof(RoutedEventHandler), typeof(Pager)); PreviousPageEvent = EventManager.RegisterRoutedEvent("PreviousPage", RoutingStrategy.Direct,
typeof(RoutedEventHandler), typeof(Pager)); NextPageEvent = EventManager.RegisterRoutedEvent("NextPage", RoutingStrategy.Direct,
typeof(RoutedEventHandler), typeof(Pager)); LastPageEvent = EventManager.RegisterRoutedEvent("LastPage", RoutingStrategy.Direct,
typeof(RoutedEventHandler), typeof(Pager)); //注册自定义的依赖属性 CurrentPageProperty = DependencyProperty.Register("CurrentPage",
typeof(string), typeof(Pager), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnCurrentPageChanged))); TotalPageProperty = DependencyProperty.Register("TotalPage",
typeof(string), typeof(Pager), new PropertyMetadata(string.Empty, new PropertyChangedCallback(OnTotalPageChanged))); #endregion } public event RoutedEventHandler FirstPage { add { AddHandler(FirstPageEvent, value); } remove { RemoveHandler(FirstPageEvent, value); } } public event RoutedEventHandler PreviousPage { add { AddHandler(PreviousPageEvent, value); } remove { RemoveHandler(PreviousPageEvent, value); } } public event RoutedEventHandler NextPage { add { AddHandler(NextPageEvent, value); } remove { RemoveHandler(NextPageEvent, value); } } public event RoutedEventHandler LastPage { add { AddHandler(LastPageEvent, value); } remove { RemoveHandler(LastPageEvent, value); } } /// <summary> /// 依赖属性回调方法 /// </summary> /// <param name="d"></param> /// <param name="e"></param> public static void OnTotalPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Pager p = d as Pager; if (p != null) { Run rTotal = (Run)p.FindName("rTotal"); rTotal.Text = (string)e.NewValue; } } private static void OnCurrentPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { Pager p = d as Pager; if (p != null) { Run rCurrrent = (Run)p.FindName("rCurrent"); rCurrrent.Text = (string)e.NewValue; } } private void FirstPageButton_Click(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(FirstPageEvent, this)); } private void PreviousPageButton_Click(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(PreviousPageEvent, this)); } private void NextPageButton_Click(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(NextPageEvent, this)); } private void LastPageButton_Click(object sender, RoutedEventArgs e) { RaiseEvent(new RoutedEventArgs(LastPageEvent, this)); } }
上面就是自定义的一个分页控件,如果我们想要使用这个控件,如下:
<Window x:Class="WPFDataGridPaging.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:WPFDataGridPaging" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <DataGrid Grid.Row="0" ItemsSource="{Binding FakeSource}" AutoGenerateColumns="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTextColumn Header="Item Id" Binding="{Binding Id}" Width="80"/> <DataGridTextColumn Header="Item Name" Binding="{Binding ItemName}" Width="180"/> </DataGrid.Columns> </DataGrid> <!-- TotalPage 和CurrentPage就是在Pager中自定义的依赖属性,可以在这里直接来用--> <local:Pager TotalPage="{Binding TotalPage}" CurrentPage="{Binding CurrentPage, Mode=TwoWay}" HorizontalAlignment="Center" Grid.Row="1"> <i:Interaction.Triggers> <!--EventName="FirstPage" 这里FirstPage就是前面注册事件的时候默认的事件名称,必须要唯一 --> <i:EventTrigger EventName="FirstPage"> <i:InvokeCommandAction Command="{Binding FirstPageCommand}" /> </i:EventTrigger> <i:EventTrigger EventName="PreviousPage"> <i:InvokeCommandAction Command="{Binding PreviousPageCommand}"/> </i:EventTrigger> <i:EventTrigger EventName="NextPage"> <i:InvokeCommandAction Command="{Binding NextPageCommand}" /> </i:EventTrigger> <i:EventTrigger EventName="LastPage"> <i:InvokeCommandAction Command="{Binding LastPageCommand}"/> </i:EventTrigger> </i:Interaction.Triggers> </local:Pager> </Grid> </Window>
界面:
后台代码:
/// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); //这里一定要注意,一定要将模型加到上下文中,要不然依赖属性和事件都不会触发,在实际开发中是不可能一打开 //界面就开始加载出来数据的,所以可以通过ObservableCollection形式绑定表格数据, //而需要绑定事件和依赖属性的需要将其绑定到上下文中 DataContext = new MainViewModel(); } }
MainViewModel:
public class MainViewModel : ViewModel { private ICommand _firstPageCommand; public ICommand FirstPageCommand { get { return _firstPageCommand; } set { _firstPageCommand = value; } } private ICommand _previousPageCommand; public ICommand PreviousPageCommand { get { return _previousPageCommand; } set { _previousPageCommand = value; } } private ICommand _nextPageCommand; public ICommand NextPageCommand { get { return _nextPageCommand; } set { _nextPageCommand = value; } } private ICommand _lastPageCommand; public ICommand LastPageCommand { get { return _lastPageCommand; } set { _lastPageCommand = value; } } private int _pageSize; public int PageSize { get { return _pageSize; } set { if(_pageSize != value) { _pageSize = value; OnPropertyChanged("PageSize"); } } } private int _currentPage; public int CurrentPage { get { return _currentPage; } set { if(_currentPage != value) { _currentPage = value; OnPropertyChanged("CurrentPage"); } } } private int _totalPage; public int TotalPage { get { return _totalPage; } set { if(_totalPage != value) { _totalPage = value; OnPropertyChanged("TotalPage"); } } } /// <summary> /// ObservableCollection表示一个动态数据集合,它可在添加、删除项目或刷新整个列表时提供通知。 /// 在xaml中绑定FakeSource之后,运行中FakeSource这里的数据改变的话 /// </summary> private ObservableCollection<FakeDatabase> _fakeSoruce; public ObservableCollection<FakeDatabase> FakeSource { get { return _fakeSoruce; } set { if(_fakeSoruce != value) { _fakeSoruce = value; OnPropertyChanged("FakeSource"); } } } private List<FakeDatabase> _source; public MainViewModel() { _currentPage = 1; _pageSize = 20; FakeDatabase fake = new FakeDatabase(); _source = fake.GenerateFakeSource(); _totalPage = _source.Count / _pageSize; _fakeSoruce = new ObservableCollection<FakeDatabase>(); List<FakeDatabase> result = _source.Take(20).ToList(); _fakeSoruce.Clear(); _fakeSoruce.AddRange(result); _firstPageCommand = new DelegateCommand(FirstPageAction); _previousPageCommand = new DelegateCommand(PreviousPageAction); _nextPageCommand = new DelegateCommand(NextPageAction); _lastPageCommand = new DelegateCommand(LastPageAction); } private void FirstPageAction() { CurrentPage = 1; var result = _source.Take(_pageSize).ToList(); _fakeSoruce.Clear(); _fakeSoruce.AddRange(result); } private void PreviousPageAction() { if(CurrentPage == 1) { return; } List<FakeDatabase> result = new List<FakeDatabase>(); if(CurrentPage == 2) { result = _source.Take(_pageSize).ToList(); } else { result = _source.Skip((CurrentPage - 2) * _pageSize).Take(_pageSize).ToList(); } _fakeSoruce.Clear(); _fakeSoruce.AddRange(result); CurrentPage--; } private void NextPageAction() { if(CurrentPage == _totalPage) { return; } List<FakeDatabase> result = new List<FakeDatabase>(); result = _source.Skip(CurrentPage * _pageSize).Take(_pageSize).ToList(); _fakeSoruce.Clear(); _fakeSoruce.AddRange(result); CurrentPage++; } private void LastPageAction() { CurrentPage = TotalPage; int skipCount = (_totalPage - 1) * _pageSize; int takeCount = _source.Count - skipCount; var result = _source.Skip(skipCount).Take(takeCount).ToList(); _fakeSoruce.Clear(); _fakeSoruce.AddRange(result); } }
其它补充代码:
DelegateCommand
public class DelegateCommand<T> : ICommand { private static bool CanExecute(T parameter) { return true; } private readonly Action<T> _execute; private Func<T, bool> _canExecute; public DelegateCommand(Action<T> execute, Func<T, bool> canExecute = null) { if (execute == null) { throw new ArgumentNullException("execute is null."); } _execute = execute; _canExecute = canExecute ?? CanExecute; } public bool CanExecute(object parameter) { return _canExecute(TranslateParameter(parameter)); } public event EventHandler CanExecuteChanged { add { if (_canExecute != null) { CommandManager.RequerySuggested += value; } } remove { if (_canExecute != null) { CommandManager.RequerySuggested -= value; } } } public void Execute(object parameter) { _execute(TranslateParameter(parameter)); } private T TranslateParameter(object parameter) { T value = default(T); if (parameter != null && typeof(T).IsEnum) value = (T)Enum.Parse(typeof(T), (string)parameter); else value = (T)parameter; return value; } } public class DelegateCommand : DelegateCommand<object> { public DelegateCommand(Action execute,Func<bool> canExecute = null) : base(obj => execute(), (canExecute == null ? null : new Func<object, bool>(obj => canExecute()))) { } }
FakeDatabase
public class FakeDatabase { public int Id { get; set; } public string ItemName { get; set; } public List<FakeDatabase> GenerateFakeSource() { List<FakeDatabase> source = new List<FakeDatabase>(); for (int i = 0; i < 1000; i++) { FakeDatabase item = new FakeDatabase() { Id = i, ItemName = "Item" + i.ToString() }; source.Add(item); } return source; } public FakeDatabase() { } }
Extension
public static class Extension { public static void AddRange<T>(this ObservableCollection<T> collection, IEnumerable<T> items) { items.ToList().ForEach(collection.Add); } }
ViewModel
public class ViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
本文中的代码转自于博客:https://www.cnblogs.com/yang-fei/p/4724899.html
ViewModel
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?