我正在使用WPF和MVVM构建应用程序。我遇到过一种情况,我有一个包含usercontrol(代表一个Timer)的视图。此usercontrol后面有一个属性代码,在获取和设置数据之前执行一些计算。
TimerControl.xaml.cs:
public DateTime? DateTimeValue
{
get
{
string hours = this.txtHours.Text;
string minutes = this.txtMinutes.Text;
string amPm = this.txtAmPm.Text;
if (!string.IsNullOrWhiteSpace(hours) && !string.IsNullOrWhiteSpace(minutes) && !string.IsNullOrWhiteSpace(amPm))
{
string value = string.Format("{0}:{1} {2}", this.txtHours.Text, this.txtMinutes.Text, this.txtAmPm.Text);
DateTime time = DateTime.Parse(value);
return time;
}
else
{
return null;
}
}
set
{
DateTime? time = value;
if (time.HasValue)
{
string timeString = time.Value.ToShortTimeString();
//9:54 AM
string[] values = timeString.Split(':', ' ');
if (values.Length == 3)
{
this.txtHours.Text = values[0];
this.txtMinutes.Text = values[1];
this.txtAmPm.Text = values[2];
}
}
}
}
现在我想将此属性绑定到视图的视图模型中的属性。以下是VM中的属性:
public DateTime? StartTime
{
get
{
return _StartTime;
}
set
{
_StartTime = value;
RaisePropertyChanged("StartTime");
}
}
这就是我在View的xaml中执行绑定的方式。
MyView.xaml:
<my:TimeControl Background="White" Grid.Column="1" Grid.Row="2" Margin="3" x:Name="StartTimeControl" DateTimeValue="{Binding StartTime}" Width="150" Height="26" HorizontalAlignment="Left">
但它给了我一个错误: 无法在“TimeControl”类型的“DateTimeValue”属性上设置“绑定”。 '绑定'只能在DependencyObject的DependencyProperty上设置。
我一直在努力想要找到一种方法来实现这种绑定工作。我甚至试图在TimeControl的代码中为DateTimeValue属性创建一个依赖属性,该属性已经解决了上述异常,但绑定仍然不起作用。每当我在后面的VM代码中访问StartTime属性时,它都显示为null。虽然它应该通过获取DateTimeValue属性来显示有效值。
请建议我一种方法来完成这项工作。谢谢。
答案 0 :(得分:2)
你想要做什么?
您无法绑定到标准属性。如果要绑定,则应使用依赖项属性。
public DateTime? DateTimeValue
{
get { return (DateTime?)GetValue(DateTimeValueProperty); }
set { SetValue(DateTimeValueProperty, value); }
}
// Using a DependencyProperty as the backing store for DateTimeValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DateTimeValueProperty =
DependencyProperty.Register("DateTimeValue", typeof(DateTime?), typeof(TimeControl), new UIPropertyMetadata(null));
在UserControl中:
<TextBox Text="{Binding DateTimeValue,RelativeSource={RelativeSource AncestorLevel=1, Mode=FindAncestor,AncestorType=UserControl}, Converter=...}" />
无法直接绑定到DateTimeValue,因为没有可用于string-&gt; DateTime的转换器,因此您必须编写IValueConverter并在绑定中指定它。
当然,你应该能够直接绑定值。
答案 1 :(得分:2)
此问题中显示的DateTimeValue属性的实现肯定是错误的并导致异常,因为DateTimeValue应该是依赖属性。
但是你提到你试图使用依赖属性但没有成功。我想原因是DataContexts碰撞,你的XAML看起来像这样:
<UserControl x:Class="Test.SomeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:self="clr-namespace:Test"
Name="Root">
<WrapPanel>
<self:TimerControl Time="{Binding StartTime}"/>
</WrapPanel>
</UserControl>
此代码不起作用。为什么? TimerControl的DataContext是继承的(或者你可以替换它),同时当你解决StartTime时,你会想到ViewModel作为DataContext。所以你应该清楚地指出正确的DataContext:
<self:Timer Time="{Binding DataContext.StartTime, ElementName=Root}"/>
===更新===
我的Timer控件的整个代码(正如你可以看到我的Timer有文本框,当你输入一些文本时,textbox会引发相应的事件,我们处理并设置Time属性):
public partial class Timer : UserControl
{
public Timer()
{
InitializeComponent();
}
public DateTime? Time
{
get
{
return (DateTime?)this.GetValue(Timer.TimeProperty);
}
set
{
this.SetValue(Timer.TimeProperty, value);
}
}
public static readonly DependencyProperty TimeProperty =
DependencyProperty.Register("Time",
typeof(DateTime?),
typeof(Timer),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (d, e) => { }));
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
if (DateTime.Now.Ticks % 2 == 0)
{
this.Time = DateTime.Now;
}
else
{
this.Time = null;
}
}
}
和XAML:
<UserControl x:Class="Test.Timer">
<Grid>
<TextBox TextChanged="TextBox_TextChanged"/>
</Grid>
</UserControl>
在XAML中使用时间控制:
<UserControl x:Class="Test.StartupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:self="clr-namespace:Test"
Name="Root">
<WrapPanel>
<self:Timer Time="{Binding DataContext.StartTime, ElementName=Root}"/>
</WrapPanel>
</UserControl>
StartupView背后的代码:
public StartupView()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
ViewModel中的属性保持不变。在调试期间,每当我在Timer中更改文本时,都会触发StartTime属性的setter。