ItemsControl-可绑定的集合-通过计时器事件更新Ui

时间:2019-07-17 23:25:26

标签: c# wpf refresh caliburn.micro itemscontrol

我正在为现场的几个传感器设备创建一个仪表板类型的UI。基于计时器的事件从数据库获取最后一条记录,并更新仪表板UI。我想动态创建我的“传感器”,它们位于BindableCollection上,然后与包含嵌套ItemsControl的XAML上的ItemsControl关联。 使用MVVM架构和Caliburn Micro进行绑定。

使用了完整属性,并确保在更新BindableColleciton之后我调用NotifyOfPropertyChange

编辑:在其他线程之后,我将System.Timer更改为DispatcherTimer(),以便更新在UI线程上运行。 DispatcherTimer vs a regular Timer in WPF app for a task scheduler

此外,由于我的BindableCollection成员始终相同,因此我确保每次都重新创建该集合,因为我有一个想法:“在添加或删除记录时,ObservableCollection会通知UI,而在编辑记录时,它不会通知UI。 。由已更改的对象来通知它已更改。”

属性:

  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刷新事件始终有效,直到我将焦点放在另一个视图上并返回为止。定时器仍在定义中,并将正确的状态放在BindableCollection上。同样,即使是简单的Int的属性也不会更新。将断点放在属性设置器上,我可以看到它从未命中,就像未触发NotifyOfPropertyChange事件一样。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

感谢大家的提示和帮助。

我已经使它工作了,有一些原因导致UI无法刷新。

  1. 如上所述,我正在使用System.Timer中的Timer。我已将它替换为DispatcherTimer,以确保事件将在与UI相同的线程上引发。
  2. 每个成员都重新创建可绑定集合,以确保触发PropertyChanged事件,因为成员是恒定的,只有属性被修改。
  3. 确保在查看swicth时取消订阅调度程序计时器事件,并在返回时再次订阅。

这是以上所有三点的结合。