XAML 数据绑定:从 DispatcherTimer 的滴答事件中设置 class 属性 时出现意外结果
XAML Data Binding: Unexpected results when setting class property from within DispatcherTimer's tick event
所有可能访问此主题的人,您好。我试图了解 XAML 数据绑定的基本原则。如您所见,这是一个简单的通用 Windows 程序。
背景: MainPage.xaml 上的绑定元素不会 从 DataContext (ClockDispatcher.cs) 接收数据如果代码放置 (A) desired location 在 class.
中执行
MainPage.xaml 上的绑定元素 将 从 DataContext (ClockDispatcher.cs) 接收数据,如果代码放置 (B) 仅测试通用绑定 在class.
中执行
调试任一代码放置选项时,本地人 windows 显示正在设置 public 属性 "MyClock.Time" IS .但是 MainPage.xaml 上的绑定元素只有在执行 CODE PLACEMENT (B) testing general binding only 时才会实现。
问题: 我的逻辑中是否存在错误,导致无法如图所示设置 class 属性 并交付该结果关联的绑定元素?请注意 class 属性 分配发生在 dispatcherTimer_Tick 方法中。
提前感谢,感谢您花时间和精力帮助我理解这个问题!
此致,
DMMcCollum
MainPage.xaml
<Page
x:Class="TestBinding.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestBinding"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:TestBinding.Models"
mc:Ignorable="d">
<Page.DataContext>
<data:ClockDispatcher />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="TimeTextBlock" Text="{Binding MyClock.Time, Mode=OneWay}" />
</StackPanel>
</Grid>
ClockDispatcher.cs
namespace TestBinding.Models
{
public class ClockDispatcher
{
//Bound to "TimeTextBlock" on MainPage.xaml
public Models.Clock MyClock { get; private set; } = new Models.Clock();
public ClockDispatcher()
{
//CODE PLACEMENT (B)
//If executed here - WILL set class public property and WILL BE reflected in UI (but not updated as understood)
//MyClock.Time = string.Format("{0}", DateTime.Now.ToString("t"));
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, object e)
{
//CODE PLACEMENT (A)
//if executed here - WILL set class public property and WILL NOT BE reflected in UI (but updates property on each tick interval as understood)
MyClock.Time = string.Format("{0}", DateTime.Now.ToString("t"));
}
}
}
Clock.cs
namespace TestBinding.Models
{
public class Clock
{
public string Time { get; set; }
}
}
您需要通知 View 您的 View Model 的更改,这是在 [=10= 的帮助下完成的] 接口(有很多关于如何实现它的信息)或使用一些 MVVM 框架,如:MVVM Light、Prism 等。 ..
INotifyPropertyChanged Interface MSDN 该示例在 Win Forms
项目中给出,但本质上与 WPF
.
相同
您可以直接将值设置到控件,但绑定不会以这种方式工作。
对于数据集合,您可以使用类似 ObservableCollection
的方式来通知视图其元素的更改,例如,您不必在添加项目时调用 Raise PropertyChanged 事件,集合会知道插入了新项目。
您应该在 class 时钟中实现 INotifyPropertyChanged,以便源或目标中的任何更改都是同步的。
为什么它在代码放置 B 中工作 - 因为 属性 值是在初始化控件之前在构造函数中设置的,因此值将始终在加载时设置。
为什么它在代码放置 A 中工作 - - 它在 window 加载后调用的不同函数中。
修复
public class 时钟:INotifyPropertyChanged
{
私有字符串时间;
public string Time
{
get
{
return this.time;
}
set
{
this.time = value;
NotifyPropertyChanged("Time");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
所有可能访问此主题的人,您好。我试图了解 XAML 数据绑定的基本原则。如您所见,这是一个简单的通用 Windows 程序。
背景: MainPage.xaml 上的绑定元素不会 从 DataContext (ClockDispatcher.cs) 接收数据如果代码放置 (A) desired location 在 class.
中执行MainPage.xaml 上的绑定元素 将 从 DataContext (ClockDispatcher.cs) 接收数据,如果代码放置 (B) 仅测试通用绑定 在class.
中执行调试任一代码放置选项时,本地人 windows 显示正在设置 public 属性 "MyClock.Time" IS .但是 MainPage.xaml 上的绑定元素只有在执行 CODE PLACEMENT (B) testing general binding only 时才会实现。
问题: 我的逻辑中是否存在错误,导致无法如图所示设置 class 属性 并交付该结果关联的绑定元素?请注意 class 属性 分配发生在 dispatcherTimer_Tick 方法中。
提前感谢,感谢您花时间和精力帮助我理解这个问题!
此致, DMMcCollum
MainPage.xaml
<Page
x:Class="TestBinding.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestBinding"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:data="using:TestBinding.Models"
mc:Ignorable="d">
<Page.DataContext>
<data:ClockDispatcher />
</Page.DataContext>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock x:Name="TimeTextBlock" Text="{Binding MyClock.Time, Mode=OneWay}" />
</StackPanel>
</Grid>
ClockDispatcher.cs
namespace TestBinding.Models
{
public class ClockDispatcher
{
//Bound to "TimeTextBlock" on MainPage.xaml
public Models.Clock MyClock { get; private set; } = new Models.Clock();
public ClockDispatcher()
{
//CODE PLACEMENT (B)
//If executed here - WILL set class public property and WILL BE reflected in UI (but not updated as understood)
//MyClock.Time = string.Format("{0}", DateTime.Now.ToString("t"));
DispatcherTimer dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += dispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, object e)
{
//CODE PLACEMENT (A)
//if executed here - WILL set class public property and WILL NOT BE reflected in UI (but updates property on each tick interval as understood)
MyClock.Time = string.Format("{0}", DateTime.Now.ToString("t"));
}
}
}
Clock.cs
namespace TestBinding.Models
{
public class Clock
{
public string Time { get; set; }
}
}
您需要通知 View 您的 View Model 的更改,这是在 [=10= 的帮助下完成的] 接口(有很多关于如何实现它的信息)或使用一些 MVVM 框架,如:MVVM Light、Prism 等。 ..
INotifyPropertyChanged Interface MSDN 该示例在 Win Forms
项目中给出,但本质上与 WPF
.
您可以直接将值设置到控件,但绑定不会以这种方式工作。
对于数据集合,您可以使用类似 ObservableCollection
的方式来通知视图其元素的更改,例如,您不必在添加项目时调用 Raise PropertyChanged 事件,集合会知道插入了新项目。
您应该在 class 时钟中实现 INotifyPropertyChanged,以便源或目标中的任何更改都是同步的。
为什么它在代码放置 B 中工作 - 因为 属性 值是在初始化控件之前在构造函数中设置的,因此值将始终在加载时设置。
为什么它在代码放置 A 中工作 - - 它在 window 加载后调用的不同函数中。
修复 public class 时钟:INotifyPropertyChanged { 私有字符串时间;
public string Time
{
get
{
return this.time;
}
set
{
this.time = value;
NotifyPropertyChanged("Time");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}