WPF应用开发之控件动态内容展示

这篇具有很好参考价值的文章主要介绍了WPF应用开发之控件动态内容展示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在我们开发一些复杂信息的时候,由于需要动态展示一些相关信息,因此我们需要考虑一些控件内容的动态展示,可以通过动态构建控件的方式进行显示,如动态选项卡展示不同的信息,或者动态展示一个自定义控件的内容等等,目的就是能够减少一些硬编码的处理方式,以及能够灵活的展示数据。本篇随笔通过实际案例介绍WPF应用开发之控件动态内容展示。

1、选项卡TabControl的动态内容展示

在我们客户关系管理模块中,往往需要展示一个客户相关的很多数据,我们可以把它们放在多个选项卡中进行统一展示,如下界面所示。

WPF应用开发之控件动态内容展示

由于客户的相关模块信息比较多,因此我们通过选项卡的展示是比较合理的一种界面组织方式,这里由于不同的客户信息,他们展示的内容不同(但结构相同),因此可以考虑动态的刷新选项卡项目TabItem的内容数据进行。

因此我们这里引入一个自定义的控件AllRelatedListControl,用来承载所有需要展示的模块一个组合。

因此在主页面上,我们可以通过一个Divider分隔控件隔开,展示客户相关的数据,如下XAML 代码所示。

<hc:Divider
    Margin="0"
    LineStroke="{DynamicResource DarkPrimaryBrush}"
    LineStrokeThickness="2" />
<Grid Margin="0,5,0,0" Background="{DynamicResource BackgroundBrush}">
    <!--  客户相关数据  -->
    <local:AllRelatedListControl x:Name="allRelatedList" CustomerId="{Binding SelectedItem.Id, ElementName=grid}" />
</Grid>

这个自定义的控件,主要的作用是组合多个选项卡项目,减少主界面的代码,并增加一些共同的属性和方法来控制数据的更新显示的。

<UserControl
    x:Class="WHC.SugarProject.CRM.WpfUI.Views.Pages.AllRelatedListControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:WHC.SugarProject.CRM.WpfUI.Views.Pages"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Name="allList"
    d:DesignHeight="450"
    d:DesignWidth="800"
    Background="{DynamicResource RegionBrush}"
    mc:Ignorable="d">
    <Grid>
        <!--  客户相关数据  -->
        <TabControl
            x:Name="tabControl"
            Height="auto"
            HorizontalAlignment="Left"
            HorizontalContentAlignment="Left"
            Background="LightCyan"
            Style="{StaticResource TabControlCapsuleSolid}"
            TabStripPlacement="Top">
            <TabItem Header="客户跟进" Tag="FollowControl">
                <local:FollowListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="联系人资料" Tag="ContactControl">
                <local:ContactListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="客户拜访" Tag="VisitControl">
                <local:VisitListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="销售机会" Tag="ChanceControl">
                <local:ChanceListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="客户文档" Tag="FileDataControl">
                <local:FileDataListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="合同文档" Tag="ContractControl">
                <local:ContractListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="产品报价" Tag="QuotationControl">
                <local:QuotationListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="客户来电" Tag="ComingCallControl">
                <local:ComingCallListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="发票记录" Tag="InvoiceControl">
                <local:InvoiceListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="维护记录" Tag="SupplierControl">
                <local:MaintenaceListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="售后服务" Tag="MaintenaceControl">
                <local:AfterSellListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="客户投诉" Tag="ComplaintControl">
                <local:ComplaintListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
            <TabItem Header="客户活动" Tag="ActivityControl">
                <local:ActivityListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>

            <TabItem Header="收货地址" Tag="">
                <local:ShippingListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
            </TabItem>
        </TabControl>
    </Grid>
</UserControl>

上面的用户控件的界面效果如下所示,它的作用就是组合多个不同的页面。

WPF应用开发之控件动态内容展示

 和其他自定义控件一样,我们增加一些自定义的属性,如这里是客户的ID,用于赋值后刷新相关的数据的。

        /// <summary>
        /// 客户ID
        /// </summary>
        public string? CustomerId
        {
            get { return (string?)GetValue(CustomerIdProperty); }
            set { SetValue(CustomerIdProperty, value); }
        }

        public static readonly DependencyProperty CustomerIdProperty = DependencyProperty.Register(
            nameof(CustomerId), typeof(string), typeof(AllRelatedListControl),
            new FrameworkPropertyMetadata("-1", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(OnCustomerIdPropertyChanged)));


        private static async void OnCustomerIdPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is not AllRelatedListControl control)
                return;

            if (control != null)
            {
                var oldValue = (string?)e.OldValue;  // 旧的值
                var newValue = (string?)e.NewValue; // 更新的新的值

                //更新数据源
                await control.InitData(newValue);
            }
        }

而我们每个子控件里面,其实也是已经根据父控件的客户ID进行了绑定属性了,如下所示。

<TabItem Header="客户跟进" Tag="FollowControl">
    <local:FollowListControl CustomerId="{Binding CustomerId, ElementName=allList}" />
</TabItem>

如果我们要根据数据库的配置信息,用来判断哪个选项卡显示或者隐藏,那么可以进一步进行处理每个TabItem的Visibility即可

//判断是否显示
foreach (TabItem item in this.tabControl.Items)
{
    if (!item.Tag.IsEmpty())
    {
        item.Visibility = CustomerTabItems.Contains(item.Tag.ToString()!) ? Visibility.Visible : Visibility.Collapsed;
    }
}

在DataGrid的鼠标键按下左键的时候,我们刷新对应自定义控件的属性CustomerId,就可以刷新相关的客户数据了。

    /// <summary>
    /// 选中每个客户记录的时候,触发更新客户相关信息
    /// </summary>
    private async void grid_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        if (this.grid.SelectedItem is CustomerInfo selectItem)
        {
            allRelatedList.CustomerId = selectItem.Id;
            await allRelatedList.InitData(selectItem.Id);
        }
    }

以上就是对于复杂的客户信息内容,使用选项卡动态组合的方式,实现内容的动态展示处理操作。

 

2、动态自定义表单内容的展示

有时候,我们在工作流表单中,需要展示一些固定的申请单信息,以及根据不同流程的表单数据(结构也不同)进行展示,如工作流中,不同的表单数据结构是不同的。

WPF应用开发之控件动态内容展示

 明细展示效果如下所示。

WPF应用开发之控件动态内容展示

或者

WPF应用开发之控件动态内容展示

可以看出不同的流程类型表单,它们的表单结构是不同的,如果我们在一个固定的页面里面展示数据,那么这块表单的数据展示,就需要用到动态控件的展示方式。

我们采用Grid布局排版方式,grid.row=0为固定表单(这里不再赘述),grid.row=1为动态表单内容,如下所示。

<StackPanel Grid.Row="1" Margin="0,20,0,0">
    <TextBlock
        HorizontalAlignment="Center"
        Style="{StaticResource TextBlockSubTitleBold}"
        Text="表单信息" />
    <Frame x:Name="formContent" />
</StackPanel>

其中里面<Frame x:Name="formContent" /> 就是我们根据实际表单的内容进行动态展示的地方。

/// <summary>
/// 该事件在loaded之后执行,也是在所有元素渲染结束之后执行
/// </summary>
/// <param name="e"></param>
protected override async void OnContentRendered(EventArgs e)
{
    base.OnContentRendered(e);

    //动态构建表单内容展示 formContent
    var formId = this.ViewModel.Item.FormId;
    if(!formId.IsNullOrEmpty())
    {
        var formInfo = await BLLFactory<IFormService>.Instance.GetAsync(formId);
        if(formInfo != null && !formInfo.ApplyWpfview.IsNullOrEmpty())
        {
            var control = ReflectionUtil.CreateInstance(formInfo.ApplyWpfview);
            var data = control as IApplyInit;
            if(data != null)
            {
                await data.InitData(this.ViewModel.Item.Id);
            }
            formContent.Content = control;
        }
    }

    //初始化工具栏
    await InitToolBar();
}

我们根据表单ID获取对应的formInfo.ApplyWpfview 属性配置,他就是一个具体的控件的名称路径,因此我们根据这个来进行反射构建一个实例,并把它转换为 IApplyInit 的接口实例,进行调用控件初始化即可。

生成的控件当做Frame控件的Content,从而实现动态内容的展示了。

我们以第一个表单【故障维修】的自定义控件定义来看看

public partial class MaintenanceViewControl : INavigableView<MaintenanceEditViewModel>, IApplyInit

它实现了 IApplyInit 接口,因此我们可以在动态控件的时候,把它转换为接口实例进行调用,这也是我们约束动态控件实例的一个规则。

不同的控件,他们的数据模型肯定不同,因此由它们自己本身实现具体的获取数据即可。

/// <summary>
/// 初始化相关业务表单数据
/// </summary>
/// <param name="applyId">申请单Id</param>
/// <returns></returns>
public async Task InitData(string applyId)
{
    this.ViewModel.Item = await BLLFactory<IMaintenanceService>.Instance.FindByApplyId(applyId);
    this.ViewModel.NotifyChanged();
}

这样我们自定义控件的XAML就可以顺利绑定对应的数据展示了,这些控件的内容,可以根据数据库接口,使用我们的代码生成工具进行快速生成,然后进行一定的裁剪调整即可,不必要一个个来编写代码。

<StackPanel hc:TitleElement.TitleWidth="100">
    <hc:Row>
        <hc:Col Span="12">
            <TextBox
                x:Name="txtDeviceName"
                Margin="5"
                hc:TitleElement.Title="故障设备名称"
                hc:TitleElement.TitlePlacement="Left"
                IsReadOnly="True"
                Text="{Binding ViewModel.Item.DeviceName}" />
        </hc:Col>
        <hc:Col Span="12">
            <DatePicker
                x:Name="txtRepairDate"
                Margin="5"
                hc:InfoElement.Title="报修日期"
                hc:InfoElement.TitlePlacement="Left"
                IsEnabled="False"
                SelectedDate="{Binding ViewModel.Item.RepairDate, StringFormat='yyyy-MM-dd'}"
                Style="{StaticResource DatePickerExtend}" />

        </hc:Col>
    </hc:Row>
    <hc:Row>
        <hc:Col>
            <TextBox
                x:Name="txtFaultDescription"
                Margin="5"
                hc:TitleElement.Title="故障描述"
                hc:TitleElement.TitlePlacement="Left"
                IsReadOnly="True"
                Text="{Binding ViewModel.Item.FaultDescription}" />
        </hc:Col>
    </hc:Row>
    <hc:Row>
        <hc:Col Span="12">
            <TextBox
                x:Name="txtRepairFee"
                Margin="5"
                hc:TitleElement.Title="预计维修费用"
                hc:TitleElement.TitlePlacement="Left"
                IsReadOnly="True"
                Text="{Binding ViewModel.Item.RepairFee}" />
        </hc:Col>
        <hc:Col Span="12" />
    </hc:Row>

    <hc:Row>
        <hc:Col Span="24">
            <TextBox
                x:Name="txtNote"
                Height="50"
                Margin="5"
                VerticalAlignment="Top"
                VerticalContentAlignment="Top"
                hc:TitleElement.Title="备注信息"
                hc:TitleElement.TitlePlacement="Left"
                AcceptsReturn="True"
                IsReadOnly="True"
                Text="{Binding ViewModel.Item.Note}" />
        </hc:Col>
    </hc:Row>
    <hc:Row>
        <hc:Col>
            <control:AttachmentControl AttachmentGUID="{Binding ViewModel.Item.AttachGUID}" Text="相关附件" />
        </hc:Col>
    </hc:Row>
</StackPanel>

可以看到这部分的代码,和我们生成的编辑界面的内容是相似的,只是进行了适量的裁剪处理,以及增加一些自定义控件,统一界面效果(如附件控件的展示)。

 

以上就是两种不同方式,动态构建不同的内容展示的处理,动态内容可以带来很好的处理便利,不过也不要滥用,比较反射太多还是会牺牲一些UI的性能,不过总体来说肯定是值得的,而且这也是一种UI的处理模式。文章来源地址https://www.toymoban.com/news/detail-747782.html

到了这里,关于WPF应用开发之控件动态内容展示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 使用DevExpress22.X(Patch)控件库在VisualStudio2022使用C#进行Winform、WPF应用的开发,看这一篇就够了!

            写在开头,Dev Express是个十分强大的控件库(下文简称Dev),但碍于其高昂的使用费用,“出于学习目的”,我们一般使用的都是Patch版本(在版权意识日趋加强的当下,不要提那两个字,现在加上那些字,百度都搜不出内容)。         最重要的 Patch资源 (包括

    2024年02月09日
    浏览(93)
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(8) -- 使用Converter类实现内容的转义处理

    在我们WPF应用端的时候,和WInform开发或者Vue前端开发一样,有时候也需要对内容进行转义处理,如把一些0,1数值转换为具体含义的文本信息,或者把一些布尔变量转换为是否等,都是常见的转换处理,本篇随笔介绍在WPF应用端对内容使用Converter类实现内容的转义处理的操作。

    2024年02月08日
    浏览(47)
  • 循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(9) -- 实现系统动态菜单的配置和权限分配

    在WPF应用端开发,它的界面类似于Winform端,因此我们也需要对系统的菜单进行动态配置,这样才能把系统的功能弹性发挥到极致,通过动态菜单的配置方式,我们可以很容易的为系统新增所需的功能,通过权限分配的方式,可以更有效的管理系统的菜单分配到不同的角色用户

    2024年02月08日
    浏览(97)
  • WPF应用开发之附件管理

    在我们之前的开发框架中,往往都是为了方便,对附件的管理都会进行一些简单的封装,目的是为了方便快速的使用,并达到统一界面的效果,本篇随笔介绍我们基于SqlSugar开发框架的WPF应用端,对于附件展示和控件的一些封装处理界面效果,供大家参考斧正。 由于我们统一

    2024年02月05日
    浏览(41)
  • 使用WPF开发BLE应用

    使用.NET Framework 先上官方文档: 蓝牙 GATT 客户端,文档是关于UWP开发BLE的,WPF如果要使用BLE的API,得手动添加几个引用(可参考这篇文章),该文章说需要添加3个引用,不过我创建的WPF应用默认已经有 WindowBase 引用,只添加了一个 Windows.winmd 引用就可以使用BLE相关的API了,另

    2024年02月03日
    浏览(52)
  • PyQt5桌面应用开发(16):定制化控件-QPainter绘图

    PyQt5桌面应用开发(1):需求分析 PyQt5桌面应用开发(2):事件循环 PyQt5桌面应用开发(3):并行设计 PyQt5桌面应用开发(4):界面设计 PyQt5桌面应用开发(5):对话框 PyQt5桌面应用开发(6):文件对话框 PyQt5桌面应用开发(7):文本编辑+语法高亮与行号 PyQt5桌面应用开

    2024年02月06日
    浏览(56)
  • Android应用开发-Flutter的LongPressDraggable控件回调函数onDraggableCanceled使用

    以下是如何使用 onDraggableCanceled 的示例: velocity 参数表示拖动被取消时的速度信息。 offset 参数表示拖动被取消时的偏移量信息。 这个回调通常用于在拖动被取消时执行一些清理工作或展示一些反馈。例如,你可能想要将拖动对象返回到原始位置,或者显示一个提示,告诉用

    2024年03月08日
    浏览(42)
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:组件内容模糊)

    为当前组件添加内容模糊效果。 说明: 从API Version 10开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 foregroundBlurStyle(value: BlurStyle, options?: ForegroundBlurStyleOptions) 为当前组件提供内容模糊能力。 系统能力:  SystemCapability.ArkUI.ArkUI.Full 参数: 参数

    2024年03月09日
    浏览(56)
  • Harmony应用开发——Web组件实现文章内容显示

            Web组件用于在应用程序中显示Web页面内容,为开发者提供页面加载、页面交互、页面调试等能力。 页面加载:Web组件提供基础的前端页面加载的能力,包括加载网络页面、本地页面、Html格式文本数据。 页面交互:Web组件提供丰富的页面交互的方式,包括:设置前

    2024年02月02日
    浏览(51)
  • 移动应用开发实验-内容提供者-ContentResolver的使用

    本人将所学和前人的成果和经验结合,仅供学习和参考!!! 本文大部分源码内容有清晰的注释,请认真阅读! 通过线性布局和相对布局来搭建通讯录界面,界面效果如下图所示。创建布局文件contact_item.xml、导入界面图片、放置界面控件、创建条目界面的背景文件。创建

    2024年02月08日
    浏览(52)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包