PLC-IoT 网关开发札记(6): Xamarin.Forms 的 CollectionView 绑定了什么?

这篇具有很好参考价值的文章主要介绍了PLC-IoT 网关开发札记(6): Xamarin.Forms 的 CollectionView 绑定了什么?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

需求:使用 CollectionView 呈现数据列表和按钮动作

项目开发中不可避免地会遇到在一个页面中呈现列表的情况,使用 CollectionView 作为容器是很方便的。CollectionView 中显示的数据对应于后台的一个 IEnumerable 派生的列表,常用的是 List<T> 和 Vector<T>,我习惯于使用 List<T> 作为后台的数据表。

CollectionView 的每一项对应后台的 List<T> 的一条记录。在网关应用中,有一个页面要列出所有的场景,单击(不论是鼠标还是手指单点一下)执行这个场景,单击条目右侧的“配置...”按钮对这个场景进行配置。

PLC-IoT 网关开发札记(6): Xamarin.Forms 的 CollectionView 绑定了什么?,visual studio,android,c#11.0,物联网

CollectionView 的 SelectionMode=“Single”,SelectionChanged 事件响应对这个条目的单击。在这个页面中,CollectionView 的每一条用一个 Grid 包装,包括了一个引导图标,一个主条目 Label 显示这个场景的名称,一个付条目 Labe 显示这个场景的类型,右侧的装填了一个“配置”按钮。 两个 Label 的 Text 可以在 XAML 中用显示绑定的方式显示对应的属性,但问题来了,“配置”按钮应该绑定什么呢?也就是说,对这个条目中包含的无绑定控件,怎么判断是哪一个条目的“配置”按钮被点击了呢?

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="I2oT.Views.ScenesPage"
             Title="场景">

    <ContentPage.Resources>
        <Style TargetType="Button">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal" >
                            <VisualState.Setters>
                                <Setter Property="Scale" Value="1" />
                            </VisualState.Setters>
                        </VisualState>

                        <VisualState x:Name="Pressed">
                            <VisualState.Setters>
                                <Setter Property="Scale" Value="0.9" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>

            <Setter Property="TextColor" Value="{StaticResource AppForegroundColor}"/>
            <Setter Property="BackgroundColor" Value="{StaticResource AppBackgroundColor}"/>
            <Setter Property="FontSize" Value="Caption"/>
            <Setter Property="HeightRequest" Value="32"/>
            <Setter Property="MinimumHeightRequest" Value="10"/>
            <Setter Property="CornerRadius" Value="2"/>
            <Setter Property="Padding" Value="4"/>
            <Setter Property="HorizontalOptions" Value="Start"/>

        </Style>

        <Style x:Key="ItemButtonStyle" TargetType="Button">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal" >
                            <VisualState.Setters>
                                <Setter Property="Scale" Value="1" />
                            </VisualState.Setters>
                        </VisualState>

                        <VisualState x:Name="Pressed">
                            <VisualState.Setters>
                                <Setter Property="Scale" Value="0.8" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>

            <Setter Property="TextColor" Value="{StaticResource AppTextCommonColor}"/>
            <Setter Property="BackgroundColor" Value="Transparent"/>
            <Setter Property="FontSize" Value="Caption"/>
            <Setter Property="HeightRequest" Value="32"/>
            <Setter Property="MinimumHeightRequest" Value="10"/>
            <Setter Property="BorderColor" Value="{StaticResource AppTextCommonColor}"/>
            <Setter Property="BorderWidth" Value="0.5"/>
            <Setter Property="CornerRadius" Value="2"/>
            <Setter Property="Padding" Value="4"/>
            <Setter Property="VerticalOptions" Value="Center"/>
            <Setter Property="HorizontalOptions" Value="Start"/>
            <Setter Property="Margin" Value="4,0"/>
            <Setter Property="CharacterSpacing" Value="1"/>
        </Style>
    </ContentPage.Resources>

    <ContentPage.ToolbarItems>
        <ToolbarItem Text="刷新" Clicked="RefreshSubsetList"/>
        <ToolbarItem Text="添加" Clicked="OnAddSceneClicked"/>
    </ContentPage.ToolbarItems>

    <CollectionView x:Name="collectionView"
                Margin="{StaticResource PageMargin}"
                SelectionMode="Single"
                SelectionChanged="OnSelectionChanged">

        <CollectionView.Header>
            <ScrollView Orientation="Horizontal">
                <StackLayout Orientation="Horizontal" >
                    <Button x:Name="btnInstantScene" Text="即时场景" Clicked="DisplayInstantScenes"/>
                    <Button x:Name="btnTimingScene" Text="定时场景" Clicked="DisplayTimingScenes"/>
                    <Button x:Name="btnSensorScene" Text="自动化场景" Clicked="DisplaySensorScenes"/>
                </StackLayout>
            </ScrollView>
        </CollectionView.Header>

        <CollectionView.ItemsLayout>
            <LinearItemsLayout Orientation="Vertical" ItemSpacing="8" />
        </CollectionView.ItemsLayout>

        <CollectionView.ItemTemplate>
            <DataTemplate>
                <StackLayout>
                    <Grid ColumnDefinitions="0.15*,*,0.4*">
                        <Image Grid.RowSpan="2"
                               Source="scene.png"
                               Aspect="AspectFit"
                               VerticalOptions="Start"
                               HeightRequest="20"
                               BackgroundColor="Transparent"/>
                        
                        <Label Grid.Row ="0"
                               Grid.Column="1"
                               Text="{Binding Name}"
                               FontSize="Small"
                               TextColor="{Binding ViewColor}"
                               BackgroundColor="Transparent"/>

                        <Label Grid.Row ="1" 
                               Grid.Column="1"
                               Text="{Binding Descriptive}"
                               TextColor="{StaticResource DescriptiveTextColor}"
                               FontSize="Caption" 
                               BackgroundColor="Transparent"/>

                        <Button Grid.RowSpan="2" Grid.Row="0" Grid.Column="2"
                                Text="配置..." Style="{StaticResource ItemButtonStyle}"
                                Clicked="OnDefineScene"/>
                    </Grid>
                </StackLayout>
            </DataTemplate>
        </CollectionView.ItemTemplate>

        <CollectionView.Footer>
            <Label x:Name="lbMessage" 
                   Text="Status"
                   FontSize="Caption" 
                   TextColor="{StaticResource AppTipIconColor}"
                   VerticalOptions="EndAndExpand"
                   HorizontalOptions="FillAndExpand"
                   HorizontalTextAlignment="Center"/>
        </CollectionView.Footer>
    </CollectionView>
</ContentPage>

Xamarin.Forms 的 CollectionView 中的子控件的 BindingContext

一开始我也对这个“绑定”感到手足无措,后来突然想到了一个办法:使用 Debug 模式,断点运行到 OnDefineScene 函数中,用 Shift+F9 查看一下是否有可用的线索。果然找到了!原来,在 CollectionView 条目中定义的子控件,不论是否显示地使用 {Binding xxxProperty} 进行绑定,这些子控件的 BindingContext 竟然就是被绑定列表的对应记录!

cs 代码

using I2oT.Data;
using I2oT.Models;
using I2oT.Views.Scenes;
using I2oT.Views.Subsets;
using I2oT.Views.SystemSettings;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace I2oT.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ScenesPage : ContentPage
    {
        private List<SceneModel> sceneList = null;
        private List<SceneModel> instantSceneList = null;
        private List<SceneModel> timingSceneList = null;
        private List<SceneModel> sensorSceneList = null;

        public ScenesPage()
        {
            InitializeComponent();
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            RefreshSceneList(this, new EventArgs());
            lbMessage.Text = "";
        }

        private void RefreshSceneList(object sender, EventArgs e)
        {
            collectionView.ItemsSource = null;
            sceneList = (new SceneModel()).GetAll();
            collectionView.ItemsSource = sceneList;

            instantSceneList = new List<SceneModel>();
            timingSceneList = new List<SceneModel>();
            sensorSceneList = new List<SceneModel>();

            foreach (var sx in sceneList)
            {
                if (sx.Type == 1)
                {
                    instantSceneList.Add(sx);
                }
                else if (sx.Type == 2)
                {
                    timingSceneList.Add(sx);
                }
                else if (sx.Type == 3)
                {
                    sensorSceneList.Add(sx);
                }
            }

            btnInstantScene.Text = "即时场景 " + instantSceneList.Count().ToString();
            btnTimingScene.Text = "定时场景 " + timingSceneList.Count().ToString();
            btnSensorScene.Text = "自动化场景 " + sensorSceneList.Count().ToString();
        }

        private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (sender == null || e == null) return;

            SceneModel scene = (SceneModel)e.CurrentSelection.FirstOrDefault();
            if (scene == null) return;

            if (scene.Type != 1) return;

            // Only instant scene can be performed directly.
            if (scene.Type == 1)
            {
                App.Gateway.PerformScene(scene.ID);
                RefreshSubsetList(null, new EventArgs());
            }
        }

        private void OnDefineScene(object sender, EventArgs e)
        {
            var sx = (SceneModel)(((Button)sender).BindingContext);

            switch (sx.Type)
            {
                case 1:
                case 3:
                    Shell.Current.GoToAsync($"{nameof(InstantSceneDefinePage)}?{nameof(InstantSceneDefinePage.SceneID)}={sx.ID}");
                    break;
                case 2:
                    string uri = "";
                    uri += $"{nameof(TimingSceneDefinePage)}?";
                    uri += $"{nameof(TimingSceneDefinePage.SceneID)}={sx.ID}&";
                    uri += $"{nameof(TimingSceneDefinePage.SceneName)}={sx.Name}";

                    Shell.Current.GoToAsync(uri);
                    break;

                default:
                    break;
            }
        }

        private void OnAddSceneClicked(object sender, EventArgs e)
        {
            Shell.Current.GoToAsync($"{nameof(AddNewScenePage)}");
        }

        private void DisplayInstantScenes(object sender, EventArgs e)
        {
            collectionView.ItemsSource = instantSceneList;
        }

        private void DisplayTimingScenes(object sender, EventArgs e)
        {
            collectionView.ItemsSource = timingSceneList;
        }

        private void DisplaySensorScenes(object sender, EventArgs e)
        {
            collectionView.ItemsSource = sensorSceneList;
        }
    }
}

上述代码中,在 OnAppearing 方法中调用 RefreshSceneList 方法获取已定义的场景列表,列表中的每一个元素是一个 SceneModel (场景的数据模型),默认将全部场景列出,通过 ItemsSource 属性将 sceneList 绑定到 CollectionView。

断点观察

在 OnDefineScene 事件的第一条语句上设置断点,运行到此处暂停,然后 Shift+F9 打开快速监视,输入sender,(Button)sender,再输入((Button)sender).BindingContext,得到的计算值如下图所示。也就是说,这个配置按钮的 BindingContext 是 CollectionView 绑定的列表的当前元素!

PLC-IoT 网关开发札记(6): Xamarin.Forms 的 CollectionView 绑定了什么?,visual studio,android,c#11.0,物联网

哦吼,这下好办啦!直接将这个 SceneModel 的 ID 传递给下级页面就可以啦~

总结

一旦 CollectionView 的 ItemsSource 被赋值为一个类的列表,那么这个 CollectionView 的每一个条目中的任何控件的默认 BindingContext 就是这个列表的当前元素。

Xamarin.Forms 的 CollectionView 真真良心。文章来源地址https://www.toymoban.com/news/detail-817500.html

到了这里,关于PLC-IoT 网关开发札记(6): Xamarin.Forms 的 CollectionView 绑定了什么?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 峰回网关数采PLC

    例如:plc地址是192.168.1.56 峰回网关默认网关地址 192.168.3.18,或者(10.10.253.354),本案例按照3.18讲解。 1和1相连,0和电脑相连 本地电脑修改ip为192.168.3.3(和3.18能通讯即可),子网掩码255.255.255.0,网关192.168.3.1 保存后会重启 将本地地址改成30网段,可以和网关互通 1.设备信

    2024年02月05日
    浏览(52)
  • Xamarin体验:使用C#开发iOS/Android应用

    http://www.cnblogs.com/lwme/p/use-xamarin-develop-Android-iOS-app.html Xamarin是Mono创始人Miguel de Icaza创建的公司,旨在让开发者可以用C#编写iOS, Android, Mac应用程序,也就是跨平台移动开发。 简介 Xamarin是基于Mono的平台,目前主要有以下产品(更具体请见:http://xamarin.com/products): Xamarin Studio:

    2024年02月07日
    浏览(46)
  • BL120PM PLC网关,实现PLC协议转Modbus协议

    随着物联网技术的迅猛发展,人们深刻认识到在智能化生产和生活中,实时、可靠、安全的数据传输至关重要。在此背景下,高性能的物联网数据传输解决方案——协议转换网关应运而生,广泛应用于工业自动化和数字化工厂应用环境中。 钡铼技术始终坚持以用户需求为核心

    2024年01月23日
    浏览(56)
  • 物联网网关与plc怎么连接?

    物联网网关与plc怎么连接 ? 物联网是当今社会中最热门的技术之一,而物联网网关则是连接物联网设备与云平台的核心设备之一。物联网网关在连接各种传感器和设备时起着至关重要的作用。而另一种广泛应用于工业控制和自动化领域的设备是可编程逻辑控制器(Programmab

    2024年01月22日
    浏览(52)
  • 使用IOT-Tree Server连接西门子PLC S7-300/1200/1500

    IOT-Tree Server是个开源物联网软件,可以作为组态软件成为自动化系统的上位软件。她提供了接入、数据组织管理、控制逻辑和人机交互多个方面的功能。从版本0.99开始,IOT-Tree Server新增了西门子以太网驱动,能够通过以太网的方式直接访问S7-300/1200/1500. S7-200 smart好像也支持

    2024年02月03日
    浏览(60)
  • PLC物联网网关BL104实现PLC协议转MQTT、OPC UA、Modbus TCP

    随着物联网技术的迅猛发展,人们深刻认识到在智能化生产和生活中,实时、可靠、安全的数据传输至关重要。在此背景下,高性能的物联网数据传输解决方案——协议转换网关应运而生,广泛应用于工业自动化和数字化工厂应用环境中。 无缝衔接工业4.0时代 尽享数字工厂

    2024年01月21日
    浏览(68)
  • EtherNet/IP转Modbus网关以连接AB PLC

    本案例为西门子S7-1200 PLC通过捷米特 Modbus转EtherNet/IP 网关捷米特JM-EIP-RTU连接AB PLC的配置案例。 网关分别从ETHERNET/IP一侧和MODBUS一侧读写数据,存入各自的缓冲区,网关内部将缓冲区的数据进行交换,从而实现两边数据的传输。 网关做为MODBUS主站 打开GW Config软件,选择“Mo

    2024年02月15日
    浏览(51)
  • PROFINET转ETHERCAT协议网关三菱plc支持ethercat吗

    捷米特JM–ECAT-PN是自主研发的一款 PROFINET 从站功能的通讯网关。该产品主要功能是将 PROFINET 网络和 ETHERCAT 网络连接起来。 捷米特JM-ECAT-PN连接到 PROFINET 总线中做为从站使用,连接到 ETHERCAT 总线中做为从站使用。 3.技术参数 PROFINET 技术参数 网关做为 PROFINET 网络的 Device 设备

    2024年02月14日
    浏览(37)
  • 上位机软件wincc通过工业网关采集plc数据实现组态监控

    WinCC是一个组态软件,可以用于数据采集与监控、自动化控制、工业物联网等领域。WinCC可以帮助用户实现工厂自动化和过程自动化的解决方案,提供可视化的监控界面和数据采集分析功能,支持多种协议和设备,如Siemens、Modbus、OPC等。 如何使用WinCC采集PLC数据?工业网关可

    2024年02月15日
    浏览(49)
  • Profinet转EtherNet/IP网关连接AB PLC的应用案例

    西门子S7-1500 PLC(profinet)与AB PLC以太网通讯(EtherNet/IP)。本文主要介绍捷米特JM-EIP-PN的 Profinet转EtherNet/IP 网关,连接西门子S7-1500 PLC与AB PLC 通讯的配置过程,供大家参考。 1, 新建工程:运行 RSLogix 5000 程序,选择菜单 File-New,弹出对话框:  2, 在“Type”中选择控制器的

    2024年02月15日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包