WPF水流动画(使用转换器模拟逻辑门控制水流信号)

前言

在使用WPF绘制流程图并模拟水流动画时,往往既需要控制阀泵的开合,又要控制动画启停。倘若能够将阀泵的开合与动画播放建立逻辑关系,这样就能够让业务代码“专心”地去控制阀泵开关,而不需要处理界面的展示。

动画示例

说明:动画中蚂蚁线的显示与隐藏是通过属性绑定配合转换器实现的。

动画解析

1、示例中【进水阀】前是一直有水流信号的,因此只要【进水阀】开,阀后即显示水流动画(此动画受一个属性控制,用单值转换器【IValueConverter】即可);

2、【进水阀】开启后,任意一个【提升泵】开启,即可出现汇入【储水池】的水流。为了与现场情况保持一致,示例中三个泵分别对应一根支管,连接到总管。水流从泵出发,通过支管流入总管,最终汇入【储水池】。

动画实现

1、水流路径处理

①当只有一个【提升泵】开启时,不用考虑路径重叠的问题,水流动画可以由一条折线来完成。

以下为单泵开启时各个泵的水流路径:

②当有多个泵开启时,只有最左边开启的泵需要绘制完整折线,其余启动泵只需绘制【支管】的水流路线。

如下,三泵全开状态。【1#泵】绘制从泵到池的完整路径,【2#泵】【3#泵】只绘制支管路径:

如下,只有【2#泵】【3#泵】开启。【2#泵】绘制从泵到池的完整路径,【3#泵】只绘制支管路径:

2、逻辑整理

①对于【1#泵】,以上两种情况下的动画路径是相同的。动画仅受【进水阀】和【1#泵】两个开关量的影响,可将其控制逻辑等效为【与门】。

②对于【2#泵】【3#泵】,【进水阀】和泵自身的开关信号是水流动画开启的必要条件,形成第一道【与门】。第二道门则根据实际情况决定:若左侧有任意泵开启,则仅绘制支管路径,此路径的第二道门为【或门】;若左侧泵全部关闭,则绘制泵到水池的完整路径,此路径的第二道门为【或非门】。

3、逻辑门实现

逻辑门借助多值转换器(IMultiValueConverter)来实现。

①与门

internal class AndGateToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values.Any(a => !(bool)a))
        {
            return Visibility.Collapsed;
        }
        return Visibility.Visible;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

 ②或门

在属性绑定中,只能使用一个转换器,所以将【与门】的逻辑整合到【或门】中,需要进行第一道【与门】判定的参数索引通过ConverterParameter传入。

internal class OrGateToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // parameter传入的是参与第一道“与门”判定的索引,多个索引之间用逗号隔开
        List<int> andGateIndexes = parameter == null
            ? new List<int>()
            : parameter.ToString().Split(',').Select(a => System.Convert.ToInt32(a)).ToList();

        // 先进行“与门”判定
        if (andGateIndexes.Any(a => !(bool)values[a]))
        {
            return Visibility.Collapsed;
        }

        // 排除“与门”判定索引,进行“或门”判定
        for (int i = 0; i < values.Length; i++)
        {
            if (!andGateIndexes.Contains(i) && (bool)values[i])
            {
                return Visibility.Visible;
            }
        }
        return Visibility.Collapsed;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

③或非门

同样将第一道【与门】判定整合到此转换器中。

internal class NOrGateToVisibilityConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        // parameter传入的是参与第一道“与门”判定的索引,多个索引之间用逗号隔开
        List<int> andGateIndexes = parameter == null
            ? new List<int>()
            : parameter.ToString().Split(',').Select(a => System.Convert.ToInt32(a)).ToList();

        // 先进行“与门”判定
        if (andGateIndexes.Any(a => !(bool)values[a]))
        {
            return Visibility.Collapsed;
        }

        // 排除“与门”判定索引,进行“或非门”判定
        for (int i = 0; i < values.Length; i++)
        {
            if (!andGateIndexes.Contains(i) && (bool)values[i])
            {
                return Visibility.Collapsed;
            }
        }
        return Visibility.Visible;
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/639229.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【设计模式深度剖析】【5】【创建型】【原型模式】| 类比群发邮件,加深理解

&#x1f448;️上一篇:建造者模式 | 下一篇:创建型设计模式对比&#x1f449;️ 目录 原型模式(Prototype Pattern)概览定义英文原话直译 3个角色类图1. 抽象原型&#xff08;Prototype&#xff09;角色2. 具体原型&#xff08;Concrete Prototype&#xff09;角色3. 客户…

Upstream最新发布2024年汽车网络安全报告-百度网盘下载

Upstream最新发布2024年汽车网络安全报告-百度网盘下载 2024年2月7日&#xff0c;Upstream Security发布了2024年Upstream《GLOBAL AUTOMOTIVE CYBERSECURITY REPORT》。这份报告的第六版着重介绍了汽车网络安全的拐点&#xff1a;从实验性的黑客攻击发展到规模庞大的攻击&…

【文心智能体】创建一个属于自己的生活情感类智能体

文章目录 前言一、创建智能体二、体验 前言 智能体技术的快速发展&#xff0c;进一步激发了各行业开发者对其实际应用及用户需求的深入探索。 创建一个属于自己的智能体。文心一言提供了一个很好的平台。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考…

“智”造产业新生态,2024SIA上海自动化展会乘势而来!

今年两会&#xff0c;我们频频听到一个热词“新质生产力”。当前&#xff0c;“加快形成新质生产力”已成为实体经济创新发展的具体指向。如何在加快形成新质生产力的新赛道上快马加鞭&#xff0c;成为下一个时代的领跑者&#xff0c;是制造业亟需面临的思考题。 在良好的市场环…

---随笔--Redis的学习以及在Spring Boot中的整合使用(RedisTemplate、Redisson分布式锁)

---随笔--Redis的学习以及在Spring Boot中的整合使用&#xff08;RedisTemplate、Redisson分布式锁&#xff09; 引言1. 什么是Redis2. Redis的数据结构3. Redis其它常用命令4. 小插曲之Redis面试常考5. 正篇&#xff1a;Redis在Spring Boot中的使用&#xff01;&#xff08;着…

NE555+74ls160+74LS20数电数字钟Multisim仿真设计

设计框图 数字钟电路的基本组成框架图如图一所示&#xff0c;它主要由多谐振荡器、计数器、译码器和数码显示器4个部分组成。 图一 数字钟电路的基本组成&#xff08;方框图&#xff09; 2、设计方案 数字钟是一个将“时”&#xff0c;“分”&#xff0c;“秒”显示于人的视…

初始MyBatis ,详细步骤运行第一个MyBatis程序,同时对应步骤MyBatis底层剖析

1. 初始MyBatis &#xff0c;详细步骤运行第一个MyBatis程序&#xff0c;同时对应步骤MyBatis底层剖析 文章目录 1. 初始MyBatis &#xff0c;详细步骤运行第一个MyBatis程序&#xff0c;同时对应步骤MyBatis底层剖析每博一文案2. 前沿知识2.1 框架&#xff08;framework&#…

jdk17安装教程详细(jdk17安装超详细图文)

2021年9月14日JDK17 发布&#xff0c;其中不仅包含很多新语言功能&#xff0c;而且与旧版 JDK 相比&#xff0c;性能提升也非常明显。与之前 LTS 版本的 JDK 8 和 JDK 11 相比&#xff0c;JDK17 的性能提升尤为明显&#xff0c;本文将教你如何安装 相比于JDK1.8&#xff0c;JD…

【Crypto】看我回旋踢

文章目录 一、看我回旋踢二、知识点什么是ROT13&#xff1f;工作原理分析字符串格式 解题感悟 一、看我回旋踢 关键词回旋&#xff0c;盲猜ROT13 因为以 synt{ 开头&#xff0c;并以 } 结束&#xff0c;基本可以判断是ROT13 小小flag&#xff0c;拿下&#xff01; 二、知识点 …

Python中动态调用C#的dll动态链接库中方法

在Python中调用C#的dll库_哔哩哔哩_bilibili 环境准备&#xff1a; 安装 pythonnet pip install pythonnet在Python中调用C#动态链接库&#xff08;DLL&#xff09;&#xff0c;可以使用pythonnet库&#xff0c;它允许直接使用 .NET 的程序集。以下是一个示例&#xff0c;…

1+x(Java)中级题库易混淆理论题

<ALL表示小于最小 小于最高等同于小于ANY 使用USING子句&#xff0c;在使用连接字段时&#xff0c;都不能在前面加上表的前缀&#xff0c;因为此时这个字段已经是连接字段&#xff0c;不再属于某个单独的表。 数据库提供的自动将提供的数据类型数据转换为期望的数据类…

go select 原理

编译器会使用如下的流程处理 select 语句&#xff1a; 将所有的 case 转换成包含 channel 以及类型等信息的 runtime.scase 结构体。调用运行时函数 runtime.selectgo 从多个准备就绪的 channel 中选择一个可执行的 runtime.scase 结构体。通过 for 循环生成一组 if 语句&…

AIGC:AI整活!万物皆可建筑设计

在过去的一年里 AI设计爆火 各行业纷纷将之用于工作中 同时不少网友也在借助它整活 万物皆可设计 甲方骂我方案像屎一样 于是我就回馈他屎一样的方案 他有点惊喜&#xff0c;但是没话 不是吧&#xff0c;随便找了个充电头图片 也能生成建筑设计&#xff01;这都能行 鸟…

人工智能应用-实验7-胶囊网络分类minst手写数据集

文章目录 &#x1f9e1;&#x1f9e1;实验内容&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;代码&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;分析结果&#x1f9e1;&#x1f9e1;&#x1f9e1;&#x1f9e1;实验总结&#x1f9e1;&#x1f9e1; &#x1f9…

微信小程序的自定义组件

一、创建自定义组件 &#xff08;1&#xff09;定义&#xff1a; 把页面重复的代码部分封装成为一个自定义组件&#xff0c;以便在不同的页面中重复使用&#xff0c;有助于代码的维护。 &#xff08;2&#xff09;组成&#xff1a; 自定义组件的组成&#xff1a;json文件&a…

Flutter 中如何优雅地使用弹框

日常开发中&#xff0c;Flutter 弹框&#xff08;Dialog&#xff09;是我们使用频率非常高的控件。无论是提示用户信息、确认用户操作&#xff0c;还是表单填写&#xff0c;弹框都能派上用场。然而&#xff0c;看似简单的弹框&#xff0c;实际使用起来却有不少坑和使用的技巧。…

el-select可选择可搜索可输入新内容

需求&#xff1a;el-form-item添加el-select&#xff0c;并且el-select可选择可搜索可输入新内容&#xff0c;并且和其他的el-input做联动&#xff0c;如果是选择&#xff0c;那么el-input自动回填数据并且不可编辑&#xff0c;如果el-select输入新的内容&#xff0c;那么el-in…

webpack5 splitChunks分割代码

首先明确webpack 自身的打包行为 当splitChunks为false时&#xff0c;此时不启用任何打包设置 可以看到&#xff0c;静态引入全都打到一个chunk里&#xff0c;动态引入会拆分出来一个chunk,这是纯webpack无配置的打包&#xff0c; webpack会给每个模块打上标记 ,如下 { m…

【HCIP学习】RSTP和MSTP

一、RSTP&#xff08;Rapid Spanning Tree Protocol&#xff0c;快速生成树&#xff09; 1、背景&#xff1a;RSTP从STP发展而来&#xff0c;具备STP的所有功能&#xff0c;可以兼容stp运行 2、RSTP与STP不同点 &#xff08;1&#xff09;减少端口状态 STP:disabled\blockin…

抵御风险——漫谈运维核心价值和方法论

要明晰什么是运维的核心价值&#xff0c;也就是要弄明白&#xff0c;从整个软件行业运维的角色定位来看&#xff0c;运维的核心价值在哪里&#xff1f;怎样增强自己实现核心价值的能力的问题。 软件产业本质其实还是工业&#xff0c;它的产品和传统的工业产品形态虽然有巨大差…