简体   繁体   English

ItemsControl-可绑定集合-通过Timer事件更新Ui

[英]ItemsControl - Bindable Collection - Ui update by Timer Event

I am creating up a dashboard type UI for couple of sensors device that are on the field. 我正在为现场的几个传感器设备创建一个仪表板类型的UI。 A timer based event gets the last record from the DB and updates the dashboard UI. 基于计时器的事件从数据库获取最后一条记录,并更新仪表板UI。 I want to dynamically creating my "sensors" which are on BindableCollection and then associated with a ItemsControl on the XAML that contains nested ItemsControl. 我想动态创建我的“传感器”,它们位于BindableCollection上,然后与包含嵌套ItemsControl的XAML上的ItemsControl关联。 Using MVVM architecture, and Caliburn Micro for Binding. 使用MVVM体系结构和Caliburn Micro进行绑定。

Have used full property and make sure I call NotifyOfPropertyChange after updating my BindableColleciton 已使用完整属性,并确保在更新我的BindableColleciton之后我调用NotifyOfPropertyChange

Edit: Following others threads I have change the System.Timer for a DispatcherTimer() so the update runs on the UI thread. 编辑:在其他线程之后,我为DispatcherTimer()更改了System.Timer,以便更新在UI线程上运行。 DispatcherTimer vs a regular Timer in WPF app for a task scheduler WPF应用程序中的DispatcherTimer与常规Timer的比较

Moreover, because my BindableCollection members were always the same I have make sure the collection is recreated at every, as I have the idea "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." 此外,由于我的BindableCollection成员始终相同,因此我确保每次都重新创建该集合,因为我的想法是“一个ObservableCollection会在添加或删除记录时通知UI,但在编辑记录时不会通知UI。到已更改的对象,以通知它已更改。”

Properties: 属性:

  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: 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>

Event (Edited): 活动(已编辑):

 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");
        }

This is the first view / view model of my application, the UI refresh event as above always work until I have focus a different view and return to it. 这是我的应用程序的第一个视图/视图模型,上面的UI刷新事件始终有效,直到我关注另一个视图并返回它为止。 The timer is def still being triggered and placing the right state on the BindableCollection. 定时器仍在定义中,并将正确的状态放在BindableCollection上。 Also, even the properties that simple Int do not update. 同样,即使是简单的Int的属性也不会更新。 Putting a break point a the property setter I can see it never hits its like NotifyOfPropertyChange event is not triggered. 将断点放在属性设置器上,我可以看到它从未命中,就像未触发NotifyOfPropertyChange事件一样。 Any idea? 任何想法?

Thanks everyone for the tips and help. 感谢大家的提示和帮助。

I have made it work, there was a couple of things that were causing the UI not be refreshed. 我已经使它工作了,有几件事导致UI无法刷新。

  1. As mentioned above, I was using a Timer from System.Timer. 如上所述,我正在使用System.Timer中的Timer。 I have replaced it with a DispatcherTimer to ensure the events will be raised on the same thread as the UI. 我已将它替换为DispatcherTimer,以确保事件将在与UI相同的线程上引发。
  2. Recreate the bindable collection every cycle to ensure the PropertyChanged event is triggered, as the members are constant and only the properties were being modified. 每个成员都重新创建可绑定集合,以确保触发PropertyChanged事件,因为成员是恒定的并且仅属性被修改。
  3. Ensure to unsubscribe the dispatcher timer event when swicth view, and subscribe it again when returning. 确保在查看swicth时取消订阅调度程序计时器事件,并在返回时再次订阅它。

It was a combination of all the 3 points above. 这是以上所有三点的结合。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM