Это простой элемент управления датой и временем, в который добавлена функция минут и часов.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace foo.WizardElements
{
/// <summary>
/// Interaction logic for DateTimeRangeElement.xaml
/// </summary>
public partial class DateTimeRangeElement : UserControl
{
public DateTimeRangeElement()
{
InitializeComponent();
dp.DataContext = this;
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
Date = null;
Hours = 0;
Minutes = 0;
}
public static readonly DependencyProperty DateProperty = DependencyProperty.Register("Date",
typeof(DateTime?),
typeof(DateTimeRangeElement));
public DateTime? Date
{
get { return (DateTime?)GetValue(DateProperty); }
set
{
SetValue(DateProperty, value);
}
}
public static readonly DependencyProperty HoursProperty = DependencyProperty.Register("Hours",
typeof(int),
typeof(DateTimeRangeElement));
public int Hours
{
get { return (int)GetValue(HoursProperty); }
set
{
SetValue(HoursProperty, value);
}
}
public static readonly DependencyProperty MinutesProperty = DependencyProperty.Register("Minutes",
typeof(int),
typeof(DateTimeRangeElement));
public int Minutes
{
get { return (int)GetValue(MinutesProperty); }
set
{
SetValue(MinutesProperty, value);
}
}
private void TimeUpdated()
{
if(Hours > 23)
Hours = 23;
if(Minutes > 59)
Minutes = 59;
if (Date.HasValue && (Date.Value.Hour != Hours || Date.Value.Minute != Minutes))
{
Date = new DateTime(Date.Value.Year, Date.Value.Month, Date.Value.Day, Hours, Minutes, 0);
}
if ((!Date.HasValue) && (Hours > 0 || Minutes > 0))
{
var now = DateTime.Now;
Date = new DateTime(now.Year, now.Month, now.Day, Hours, Minutes, 0);
}
}
private void Changed(object sender, object e)
{
TimeUpdated();
}
}
}
и xaml
<UserControl x:Class="foo.WizardElements.DateTimeRangeElement"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behavior="clr-namespace:foo.Behaviours"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="myDateTimeControl">
<Grid>
<StackPanel Orientation="Horizontal" Margin="2" Height="24">
<DatePicker x:Name="dp"
VerticalAlignment="top"
Foreground="LightGray"
SelectedDate="{Binding ElementName=myDateTimeControl,Path=Date, Mode=TwoWay}"
BorderBrush="{x:Null}" SelectedDateChanged="Changed"
>
<DatePicker.Background>
<SolidColorBrush Color="white" Opacity="0.2"/>
</DatePicker.Background>
</DatePicker>
<TextBox Width="30" Text="{Binding ElementName=myDateTimeControl, Path=Hours, Mode=TwoWay, StringFormat=00}" TextChanged="Changed">
<i:Interaction.Behaviors>
<behavior:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]*$" MaxLength="3" />
</i:Interaction.Behaviors>
</TextBox>
<Label Content=":"/>
<TextBox Width="30" Text="{Binding ElementName=myDateTimeControl, Path=Minutes, Mode=TwoWay, StringFormat=00}" TextChanged="Changed">
<i:Interaction.Behaviors>
<behavior:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]*$" MaxLength="3" />
</i:Interaction.Behaviors>
</TextBox>
<Grid HorizontalAlignment="Left" VerticalAlignment="top">
<Button
Background="Transparent"
Click="Clear_Click"
BorderThickness="0"
>
<Grid>
<Image Source="/foo;component/Images/Clear-left.png" Stretch="Uniform"/>
</Grid>
</Button>
</Grid>
</StackPanel>
</Grid>
</UserControl>
Итак, вот пример использования, вы положили этого щенкана вкладке выберите время и дату, отойдите от вкладки и вернитесь.Если вы связываете данные только со свойством «Дата», а не с часами и минутами, вы обнаружите, что оба из них установлены на 0.
Причина этого в том, что после перехода с вкладки вы избавляетесь отпользовательский контроль, и когда вы возвращаетесь назад, вы приветствуете новый пользовательский контроль (.Net 4).
Привязка к часам и минутам является бесполезной и не имеет смысла для потребителя, поскольку он ожидает объект DateTime.
Я пытаюсь выяснить, каков будет шаблон corect для повторной загрузки часов и минут при воссоздании usercontrol.
это то, как usercontrol используется в приложении
<we:DateTimeRangeElement Date="{Binding Path=Filter.StartTime, Mode=TwoWay}" />
РЕДАКТИРОВАТЬ: У меня есть решение, которое мне не нравится, но оно будет работать, пока я не смогу избавиться от клея.я создал свой объект datetime и использовал его, чтобы получить более привязываемый объект.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;
using ToolSuite.Contract.BaseClasses;
using System.Globalization;
namespace foo.WizardElements
{
/// <summary>
/// Interaction logic for DateTimeRangeElement.xaml
/// </summary>
public partial class DateTimeRangeElement : UserControl
{
public DateTimeRangeElement()
{
InitializeComponent();
this.GotFocus += DateTimeRangeElement_GotFocus;
}
void DateTimeRangeElement_GotFocus(object sender, RoutedEventArgs e)
{
if(Date!=null)
Date.PropertyChanged += Date_PropertyChanged;
}
void Date_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
this.GetBindingExpression(DateProperty).UpdateSource();
}
private void Clear_Click(object sender, RoutedEventArgs e)
{
Date = null;
}
public static readonly DependencyProperty DateProperty = DependencyProperty.Register("Date",
typeof(FriendlyDateTime),
typeof(DateTimeRangeElement));
public FriendlyDateTime Date
{
get { return (FriendlyDateTime)GetValue(DateProperty); }
set
{
SetValue(DateProperty, value);
}
}
}
}
xaml
<UserControl x:Class="foo.WizardElements.DateTimeRangeElement"
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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behavior="clr-namespace:foo.Behaviours"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="myDateTimeControl">
<Grid>
<StackPanel Orientation="Horizontal" Margin="2" Height="24">
<DatePicker x:Name="dp"
VerticalAlignment="top"
Foreground="LightGray"
SelectedDate="{Binding ElementName=myDateTimeControl,Path=Date.Date, Mode=TwoWay}"
BorderBrush="{x:Null}"
>
<DatePicker.Background>
<SolidColorBrush Color="white" Opacity="0.2"/>
</DatePicker.Background>
</DatePicker>
<TextBox x:Name="Hours" Width="30" Text="{Binding ElementName=myDateTimeControl, Path=Date.Hour, Mode=TwoWay, StringFormat=00}">
<i:Interaction.Behaviors>
<behavior:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]*$" MaxLength="3" />
</i:Interaction.Behaviors>
</TextBox>
<Label Content=":"/>
<TextBox x:Name="Minutes" Width="30" Text="{Binding ElementName=myDateTimeControl, Path=Date.Minute, Mode=TwoWay, StringFormat=00}">
<i:Interaction.Behaviors>
<behavior:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]*$" MaxLength="3" />
</i:Interaction.Behaviors>
</TextBox>
<Grid HorizontalAlignment="Left" VerticalAlignment="top">
<Button
Background="Transparent"
Click="Clear_Click"
BorderThickness="0"
>
<Grid>
<Image Source="/foo;component/Images/Clear-left.png" Stretch="Uniform"/>
</Grid>
</Button>
</Grid>
</StackPanel>
</Grid>
</UserControl>
помощник
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ToolSuite.Contract.BaseClasses;
namespace foo.WizardElements
{
public class FriendlyDateTime : NotifyPropertyChangedBase
{
public FriendlyDateTime()
{
}
public FriendlyDateTime(DateTime? value)
{
Date = value;
}
public DateTime? Date
{
get
{
if (base._values.ContainsKey("Date"))
return Get<DateTime>("Date");
else
return null;
}
set
{
if (value == null)
{
if (base._values.ContainsKey("Date"))
base._values.Remove("Date");
}
else
Set<DateTime>("Date", value.Value);
base.NotifyPropertyChanged("Date");
base.NotifyPropertyChanged("Hour");
base.NotifyPropertyChanged("Minute");
}
}
public int Hour
{
get { return Date.HasValue ? Date.Value.Hour : 0; }
set
{
if (Hour > 23)
Hour = 23;
var d = Date.HasValue ? Date.Value : DateTime.Now;
Date = new DateTime(d.Year, d.Month, d.Day, value, Minute, 0);
}
}
public int Minute
{
get { return Date.HasValue ? Date.Value.Minute : 0; }
set
{
if (Minute > 59)
Minute = 59;
var d = Date.HasValue ? Date.Value : DateTime.Now;
Date = new DateTime(d.Year, d.Month, d.Day, Hour, value, 0);
}
}
static public implicit operator DateTime?(FriendlyDateTime value)
{
return value.Date;
}
static public implicit operator FriendlyDateTime(DateTime? value)
{
// Note that because RomanNumeral is declared as a struct,
// calling new on the struct merely calls the constructor
// rather than allocating an object on the heap:
return new FriendlyDateTime(value);
}
}
}
несколько бесполезный четверг, от которого я хотел бы избавиться
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Globalization;
using ToolSuite.Contract.BaseClasses;
namespace foo.WizardElements
{
public class FriendlyDateTimeValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(DateTime?))
{
return ((FriendlyDateTime)value).Date;
}
else if (targetType == typeof(FriendlyDateTime))
{
return new FriendlyDateTime(value as DateTime?);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (targetType == typeof(DateTime?))
{
return ((FriendlyDateTime)value).Date;
}
else if (targetType == typeof(FriendlyDateTime))
{
return new FriendlyDateTime(value as DateTime?);
}
return null;
}
}
}
и, наконец, способ его использования
<we:DateTimeRangeElement Date="{Binding Path=Filter.EndTime, Mode=TwoWay, Converter={StaticResource DateTimeConverter}, UpdateSourceTrigger=Explicit}" />
Мне это нравится?Нет, не очень хочется, чтобы я мог угробить конвертер значений и явную привязку.но это будет исследовательский проект на другой день.