ItemsControl - 可绑定集合 - Ui 由计时器事件更新
ItemsControl - Bindable Collection - Ui update by Timer Event
我正在为现场的几个传感器设备创建仪表板类型 UI。基于计时器的事件从数据库中获取最后一条记录并更新仪表板 UI。我想动态创建位于 BindableCollection 上的 "sensors",然后与包含嵌套 ItemsControl 的 XAML 上的 ItemsControl 相关联。
使用 MVVM 架构,并使用 Caliburn Micro 进行绑定。
已完全使用 属性 并确保在更新我的 BindableColleciton 后调用 NotifyOfPropertyChange
编辑:在其他线程之后,我更改了 DispatcherTimer() 的 System.Timer,因此更新在 UI 线程上运行。
DispatcherTimer vs a regular Timer in WPF app for a task scheduler
此外,因为我的 BindableCollection 成员总是相同的,所以我确保每次都重新创建集合,正如我的想法 "An ObservableCollection will notify the UI when a record is added or removed but not when a record is edited. It's up to the object that has been changed to notify that it has changed."
属性:
private int _offlineSensors;
public int OfflineSensors
{
get { return _offlineSensors; }
set
{
_offlineSensors = value;
NotifyOfPropertyChange(() => OfflineSensors);
}
}
private int _latchedAlarms;
public int LatchedAlarms
{
get { return _latchedAlarms; }
set
{
_latchedAlarms = value;
NotifyOfPropertyChange(() => LatchedAlarms);
}
}
private int _activeAlarms;
public int ActiveAlarms
{
get { return _activeAlarms; }
set
{
_activeAlarms = value;
NotifyOfPropertyChange(() => ActiveAlarms);
}
}
private Caliburn.Micro.BindableCollection<SensorStatusTable> _sensorStatusFilteredDash;
public Caliburn.Micro.BindableCollection<SensorStatusTable> SensorStatusFilteredDash
{
get { return _sensorStatusFilteredDash; }
set
{
_sensorStatusFilteredDash = value;
NotifyOfPropertyChange(() => SensorStatusFilteredDash);
}
}
XAML:
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=SensorStatusFilteredDash, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="RoyalBlue" BorderThickness="2" Margin="2" Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="20" />
<Image MaxWidth="60" MaxHeight="60" Source="{Binding CardStatusImage, Converter={StaticResource ResourceKey = ImageConverter}, UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform"></Image>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=SensorTypes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="12" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Margin="25.5,1,18,1"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=InternalSensorStatusImages, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Margin="11.5,1" MaxWidth="40" HorizontalAlignment="Center" VerticalAlignment="Center" MaxHeight="40" Source="{Binding Converter={StaticResource ResourceKey = ImageConverter}}" Stretch="Uniform"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=InternalSensorStatusDescription, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="12" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Margin="10,1,10,1"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
事件(已编辑):
var conn = GlobalConfig.Connections.FirstOrDefault(c => c.GetType() == typeof(SQLConnector));
if (conn == null) return;
try
{
ActiveAlarms = conn.GetNumberActiveAlarms(0);
LatchedAlarms = conn.GetNumberActiveAlarms(2);
GasSensors = new Caliburn.Micro.BindableCollection<GasSensor>(conn.GetGasSensors());
SensorStatusDash = new Caliburn.Micro.BindableCollection<SensorStatusTable>(conn.SensorStatusDashboard());
_sensorStatusFilteredDash.Clear();
_sensorStatusFilteredDash = new Caliburn.Micro.BindableCollection<SensorStatusTable>(StatusImageConverter());
NotifyOfPropertyChange(() => SensorStatusFilteredDash);
NotifyOfPropertyChange(() => OfflineSensors);
NotifyOfPropertyChange(() => ActiveAlarms);
NotifyOfPropertyChange(() => LatchedAlarms);
}
catch (Exception ex)
{
_logger.Error(ex, "Error - Refreshing Dashboard Status");
}
这是我的应用程序的第一个视图/视图模型,上面的 UI 刷新事件始终有效,直到我将焦点放在不同的视图上并 return 到它。计时器仍然被触发并将正确的状态置于 BindableCollection 上。此外,即使是简单 Int 的属性也不会更新。在 属性 setter 上放置一个断点,我可以看到它永远不会触发它,就像 NotifyOfPropertyChange 事件没有被触发一样。有什么想法吗?
感谢大家的提示和帮助。
我成功了,有几件事导致 UI 无法刷新。
- 如上所述,我使用的是 System.Timer 的定时器。我已将其替换为 DispatcherTimer 以确保事件将在与 UI.
相同的线程上引发
- 每个周期重新创建可绑定集合以确保触发 PropertyChanged 事件,因为成员是常量并且只有属性被修改。
- 确保在swicth视图时取消订阅dispatcher timer事件,返回时重新订阅。
以上三点的综合。
我正在为现场的几个传感器设备创建仪表板类型 UI。基于计时器的事件从数据库中获取最后一条记录并更新仪表板 UI。我想动态创建位于 BindableCollection 上的 "sensors",然后与包含嵌套 ItemsControl 的 XAML 上的 ItemsControl 相关联。 使用 MVVM 架构,并使用 Caliburn Micro 进行绑定。
已完全使用 属性 并确保在更新我的 BindableColleciton 后调用 NotifyOfPropertyChange
编辑:在其他线程之后,我更改了 DispatcherTimer() 的 System.Timer,因此更新在 UI 线程上运行。 DispatcherTimer vs a regular Timer in WPF app for a task scheduler
此外,因为我的 BindableCollection 成员总是相同的,所以我确保每次都重新创建集合,正如我的想法 "An ObservableCollection will notify the UI when a record is added or removed but not when a record is edited. It's up to the object that has been changed to notify that it has changed."
属性:
private int _offlineSensors;
public int OfflineSensors
{
get { return _offlineSensors; }
set
{
_offlineSensors = value;
NotifyOfPropertyChange(() => OfflineSensors);
}
}
private int _latchedAlarms;
public int LatchedAlarms
{
get { return _latchedAlarms; }
set
{
_latchedAlarms = value;
NotifyOfPropertyChange(() => LatchedAlarms);
}
}
private int _activeAlarms;
public int ActiveAlarms
{
get { return _activeAlarms; }
set
{
_activeAlarms = value;
NotifyOfPropertyChange(() => ActiveAlarms);
}
}
private Caliburn.Micro.BindableCollection<SensorStatusTable> _sensorStatusFilteredDash;
public Caliburn.Micro.BindableCollection<SensorStatusTable> SensorStatusFilteredDash
{
get { return _sensorStatusFilteredDash; }
set
{
_sensorStatusFilteredDash = value;
NotifyOfPropertyChange(() => SensorStatusFilteredDash);
}
}
XAML:
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=SensorStatusFilteredDash, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="RoyalBlue" BorderThickness="2" Margin="2" Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Name}" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" FontWeight="Bold" FontSize="20" />
<Image MaxWidth="60" MaxHeight="60" Source="{Binding CardStatusImage, Converter={StaticResource ResourceKey = ImageConverter}, UpdateSourceTrigger=PropertyChanged}" Stretch="Uniform"></Image>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=SensorTypes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding }" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="12" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Margin="25.5,1,18,1"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=InternalSensorStatusImages, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Margin="11.5,1" MaxWidth="40" HorizontalAlignment="Center" VerticalAlignment="Center" MaxHeight="40" Source="{Binding Converter={StaticResource ResourceKey = ImageConverter}}" Stretch="Uniform"></Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Foreground="Black" Background="Black" ItemsSource="{Binding Path=InternalSensorStatusDescription, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" TextWrapping="WrapWithOverflow" FontWeight="Bold" FontSize="12" TextAlignment="Center" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="White" Margin="10,1,10,1"></TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
事件(已编辑):
var conn = GlobalConfig.Connections.FirstOrDefault(c => c.GetType() == typeof(SQLConnector));
if (conn == null) return;
try
{
ActiveAlarms = conn.GetNumberActiveAlarms(0);
LatchedAlarms = conn.GetNumberActiveAlarms(2);
GasSensors = new Caliburn.Micro.BindableCollection<GasSensor>(conn.GetGasSensors());
SensorStatusDash = new Caliburn.Micro.BindableCollection<SensorStatusTable>(conn.SensorStatusDashboard());
_sensorStatusFilteredDash.Clear();
_sensorStatusFilteredDash = new Caliburn.Micro.BindableCollection<SensorStatusTable>(StatusImageConverter());
NotifyOfPropertyChange(() => SensorStatusFilteredDash);
NotifyOfPropertyChange(() => OfflineSensors);
NotifyOfPropertyChange(() => ActiveAlarms);
NotifyOfPropertyChange(() => LatchedAlarms);
}
catch (Exception ex)
{
_logger.Error(ex, "Error - Refreshing Dashboard Status");
}
这是我的应用程序的第一个视图/视图模型,上面的 UI 刷新事件始终有效,直到我将焦点放在不同的视图上并 return 到它。计时器仍然被触发并将正确的状态置于 BindableCollection 上。此外,即使是简单 Int 的属性也不会更新。在 属性 setter 上放置一个断点,我可以看到它永远不会触发它,就像 NotifyOfPropertyChange 事件没有被触发一样。有什么想法吗?
感谢大家的提示和帮助。
我成功了,有几件事导致 UI 无法刷新。
- 如上所述,我使用的是 System.Timer 的定时器。我已将其替换为 DispatcherTimer 以确保事件将在与 UI. 相同的线程上引发
- 每个周期重新创建可绑定集合以确保触发 PropertyChanged 事件,因为成员是常量并且只有属性被修改。
- 确保在swicth视图时取消订阅dispatcher timer事件,返回时重新订阅。
以上三点的综合。