这是一个简单的日期时间控件,它具有分钟和小时的附加功能。在用户控件中保留数据
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时重新加载小时和分钟。
这是用户控件是如何在应用程序中使用
<we:DateTimeRangeElement Date="{Binding Path=Filter.StartTime, Mode=TwoWay}" />
编辑: 我有一个解决方案,我不喜欢,但它会做,直到我能得到胶的出路。我所做的是创建我自己的日期时间对象,并使用我能够获得更多可绑定对象。
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);
}
}
}
有点没用thurd,我想摆脱
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}" />
我喜欢吗?不,我真的不希望我可以放弃价值转换器和显式绑定。但那将是另一天的研究项目。
属性是可绑定的,这就是他们如何使用。所以有一个对象具有设置为2路绑定的日期时间属性。小时和分钟导致问题。 – 2012-01-13 20:47:55
@Bas Harmer:尽我所见,他们是'UserControl'的属性,所以如果控制因任何原因而处置,属性就消失了。 – Tigran 2012-01-13 20:49:48
是的我没有显示如何使用conrol;但是如果你使用可绑定的属性而不是数据中存在的数据值。我希望保持与日期选择器控件相同的模式,但需要数小时和分钟。 – 2012-01-13 20:54:45