چگونه یک WPF DateRangePicker ایجاد کنیم؟
من به راهی نیاز داشتم که به کاربر اجازه دهد محدوده تاریخ را برای فیلتر WPF DataGrid انتخاب کند. پس از مدتی تحقیق، نتوانستم کنترلی را پیدا کنم که بتواند آنچه را که میخواستم داشته باشد، بنابراین تصمیم گرفتم کنترل کاربر WPF خود را ایجاد کنم که امکان انتخاب یک تاریخ یا محدوده تاریخ را فراهم میکند.
کنترل کاربر WPF تمام شده را می توان در نمایه GitHub من در XamlDateRangePicker پیدا کرد.
مقاله زیر فرآیند ایجاد و نحوه استفاده از کنترل را شرح خواهد داد.
برنامه ریزی
ابتدا باید برنامهریزی کنم که کنترل کاربر به چه بخشهایی نیاز دارد تا عملکرد مورد نظر من را ارائه دهد. بنابراین من یک نمونه اولیه کاغذی سریع انجام دادم.
قطعات
-
TextBox
من می خواستم تاریخ (محدوده) انتخاب شده را شبیه به DateTimePicker نشان دهم، بنابراین فکر کردم که به یک Textbox نیاز دارم. -
دکمه تصویر
یک دکمه برای باز کردن تقویم باید با TextBox ترکیب شود. من فکر کردم که ToggleButton بهترین انتخاب برای این قابلیت است، زیرا آن را داردIsChecked
حالت. -
پنجره بازشو
من می خواستم زمانی که کاربر روی دکمه Toggle کلیک می کند، تقویم از TextBox به پایین اسلاید شود، بنابراین تصمیم گرفتم یک پنجره بازشو اضافه کنم. -
تقویم
کنترل واقعی تقویم که در پنجره بازشو تو در تو قرار دارد.
ایجاد کنترل کاربر WPF
یک کنترل کاربر WPF معمولی از دو فایل تشکیل شده است.
- آ .xaml فایل
- و الف .xaml.cs فایل
UI کنترل ها در ایجاد می شود .xaml فایل و منطق آن در .xaml.cs فایل.
ایجاد رابط کاربری
ابتدا یک کنترل کاربر WPF به پروژه خود اضافه کردم تا دو فایل مورد نیاز را ایجاد کنم. سپس شروع به ویرایش کردم DateRangePicker.xaml
فایل و کنترل های مورد نیاز را اضافه کرد.
<UserControl x:Class="UserControls.DateRangePicker"
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:UserControls"
mc:Ignorable="d"
x:Name="this"
d:DesignHeight="30" d:DesignWidth="160">
<StackPanel>
<Border
BorderThickness="1"
BorderBrush="{Binding ElementName=DateRangePicker_TextBox, Path=BorderBrush}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="30" />
</Grid.ColumnDefinitions>
<TextBox
x:Name="DateRangePicker_TextBox"
Grid.Column="0"
Margin="0"
MinHeight="30"
BorderThickness="0"
d:Text="14.03.2023 - 20.03.2023"
Text="{Binding ElementName=this, Path=DisplayValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Delay=300}"
KeyUp="Handle_Escape_Button" />
<ToggleButton
x:Name="DateRangePicker_ArrowButton"
Grid.Column="1"
Height="{Binding ElementName=DateRangePicker_TextBox, Path=Height}"
Focusable="False"
ClickMode="Press"
IsChecked="{Binding ElementName=this, Path=IsDropDownOpen, Mode=TwoWay}"
MinWidth="30"
Background="{Binding ElementName=DateRangePicker_TextBox, Path=Background}"
BorderBrush="{Binding ElementName=DateRangePicker_TextBox, Path=Background}"
BorderThickness="0"
HorizontalAlignment="Right"
VerticalAlignment="Stretch">
<Path
x:Name="DateRangePicker_Arrow"
Data="M 0 0 L 4 4 L 8 0 Z">
<Path.Fill>
<SolidColorBrush Color="#FF444444"/>
</Path.Fill>
</Path>
</ToggleButton>
</Grid>
</Border>
<Popup
x:Name="DateRangePicker_Popup"
Placement="Bottom"
IsOpen="{Binding ElementName=this, Path=IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Viewbox
x:Name="DateRangePicker_DropDown"
SnapsToDevicePixels="True"
Stretch="Fill">
<Calendar
x:Name="DateRangePicker_Calendar"
SelectionMode="SingleRange"
SelectedDatesChanged="DateRangePicker_Calendar_SelectedDatesChanged"/>
</Viewbox>
</Popup>
</StackPanel>
</UserControl>
برای اطمینان از الزام آور بودن کنترل ها به کد پشت (.xaml.cs) به کاربر خود کنترل دادم x:Name="this"
. بنابراین من می توانم از آن برای مثال استفاده کنم Text
صحافی TextBox
Text="{Binding ElementName=this, Path=DisplayValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Delay=300}"
این برای a جستجو می کند DisplayValue
دارایی در من DateRangePicker.xaml.cs
فایل.
ایجاد منطق کنترل ها
سپس شروع به ویرایش کردم .xaml.cs
فایل برای اضافه کردن منطق کنترل های کاربر. در اینجا من EventHandler و Properties را تعریف کردم که در XAML کنترل استفاده می شود و همچنین یک DependencyProperty
که باید از بیرون قابل دسترسی باشد تا بتوان تاریخ (محدوده) انتخابی را دریافت کرد.
تعریف یک ویژگی وابستگی
یک ویژگی وابستگی را می توان از خارج از کنترل محدود کرد. شما باید مانند قطعه کد زیر یک ویژگی را به عنوان DependencyProperty ثبت کنید.
public static readonly DependencyProperty SelectedDateRangeProperty
= DependencyProperty.Register(
nameof(SelectedDateRange),
typeof(ObservableCollection<DateTime>),
typeof(DateRangePicker),
new FrameworkPropertyMetadata(default(ObservableCollection<DateTime>), FrameworkPropertyMetadataOptions.None));
public ObservableCollection<DateTime> SelectedDateRange
{
get => (ObservableCollection<DateTime>)GetValue(SelectedDateRangeProperty);
set => SetValue(SelectedDateRangeProperty, value);
}
به روز رسانی / تعامل با UI
به منظور به روز رسانی یا تعامل با UI از کد پشت خود، باید مطمئن شوید که آن را پیاده سازی کرده اید INotifyPropertyChanged
رابط. به طوری که می توانید هنگام تغییر هر ویژگی که در UI شما استفاده می شود، یک اعلان دریافت کنید.
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName] string propertyName = "", Action onChanged = null)
{
var output = false;
if (EqualityComparer<T>.Default.Equals(backingStore, value) == false)
{
backingStore = value;
onChanged?.Invoke();
RaisePropertyChanged(propertyName);
output = true;
}
return output;
}
سپس می توانید از SetProperty
روشی برای افزایش تغییر ویژگی که UI را به روز می کند.
در اینجا یک نمونه از SelectedDates
ویژگی که از کنترل های تقویم به روز می شود SelectedDatesChanged
رویداد.
public ObservableCollection<DateTime> SelectedDates
{
get => _selectedDate;
set => SetProperty(ref _selectedDate, value, onChanged: () =>
{
IsDropDownOpen = false;
if (value.Any())
{
if (value.Count == 1)
{
DisplayValue = value.First().ToString("dd.MM.yyyy");
SelectedDateRange = new ObservableCollection<DateTime> { value.First() };
}
else
{
DisplayValue = $"{value.First():dd.MM.yyyy} - {value.Last():dd.MM.yyyy}";
SelectedDateRange = new ObservableCollection<DateTime> { value.First(), value.Last() };
}
}
else
{
SelectedDateRange = new ObservableCollection<DateTime>();
}
});
}
private ObservableCollection<DateTime> _selectedDate = new ObservableCollection<DateTime>();
با استفاده از کنترل
برای استفاده از کنترل باید مراحل بعدی را دنبال کنید.
- پروژه یا کنترل کاربر را به راه حل/پروژه خود اضافه کنید.
- فضای نام کنترل کاربر را به XAML خود اضافه کنید
xmlns:userControls="clr-namespace:UserControls;assembly=DateRangePicker"
- از کنترل در XAML خود استفاده کنید
<userControls:DateRangePicker
SelectedDateRange="{Binding SelectedDates, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
می توانید ببندید SelectedDateRange
ویژگی ViewModel شما. این ویژگی دارای یک ObservableCollection<DateTime>
از یک یا دو تاریخ یا تاریخ انتخابی تکی یا اولین و آخرین تاریخ محدوده تاریخ انتخاب شده.