精华内容
下载资源
问答
  • 2019-10-17 18:54:53

    使用WPF封装了一个简单的ImageButton自定义控件,加入常态、划过、按下、禁用状态属性,可设置相应的图标。参考链接:https://blog.csdn.net/elie_yang/article/details/81870694

    1、ImageButton自定义控件类

        public class UCImageButton : Button
        {
            static UCImageButton()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(UCImageButton), new FrameworkPropertyMetadata(typeof(UCImageButton)));
            }
    
            #region Properties
            public static DependencyProperty NormalImageProperty = DependencyProperty.Register("NormalImage", typeof(ImageSource), typeof(UCImageButton), new PropertyMetadata(null));
            public ImageSource NormalImage
            {
                get { return (ImageSource)GetValue(NormalImageProperty); }
                set { SetValue(NormalImageProperty, value); }
            }
    
            public static readonly DependencyProperty HoverImageProperty = DependencyProperty.Register("HoverImage", typeof(ImageSource), typeof(UCImageButton), new PropertyMetadata(null));
            public ImageSource HoverImage
            {
                get { return (ImageSource)GetValue(HoverImageProperty); }
                set { SetValue(HoverImageProperty, value); }
            }
    
            public static DependencyProperty PressedImageProperty = DependencyProperty.Register("PressedImage", typeof(ImageSource), typeof(UCImageButton), new PropertyMetadata(null));
            public ImageSource PressedImage
            {
                get { return (ImageSource)GetValue(PressedImageProperty); }
                set { SetValue(PressedImageProperty, value); }
            }
    
            public static readonly DependencyProperty DisabledImageProperty = DependencyProperty.Register("DisabledImage", typeof(ImageSource), typeof(UCImageButton), new PropertyMetadata(null));
            public ImageSource DisabledImage
            {
                get { return (ImageSource)GetValue(DisabledImageProperty); }
                set { SetValue(DisabledImageProperty, value); }
            }
            #endregion
        }

    2、ImageButton的Style样式

        <!--UCImageButton样式-->
        <Style TargetType="{x:Type uc:UCImageButton}">
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Template" > 
                <Setter.Value >
                    <ControlTemplate TargetType="{x:Type uc:UCImageButton}" > 
                        <Border x:Name="border" BorderThickness="0" SnapsToDevicePixels="true">
                            <Image x:Name="img" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" Source="{TemplateBinding NormalImage}" Stretch="Fill"></Image>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Source" TargetName="img" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=HoverImage}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Source" TargetName="img" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=PressedImage}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Source" TargetName="img" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=DisabledImage}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate> 
                </Setter.Value> 
            </Setter>
        </Style>

    注意Triggers里Bind的写法,

    写成:

    <Setter Property="Source" TargetName="img" Value="{Binding HoverImage}"/> 则找不到图片一直闪烁;

    写成:

    <Setter Property="Source" TargetName="img" Value="{TemplateBinding HoverImage}"/>则会报错;

    需要写成:

    <Setter Property="Source" TargetName="img" Value="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=HoverImage}"/>

    3、xaml用法

    <uc:UCImageButton x:Name="imgBtn" NormalImage="/Resource/Image/Normal.png" HoverImage="/Resource/Image/Hover.png" PressedImage="/Resource/Image/Pressed.png"
                                                  Width="60" Height="60"></uc:UCImageButton>

    这里有个问题,封装的属性还不完善,在使用时需要指定HoverImage、PressedImage的图片路径,否则会发生闪烁,暂时还没有找到好的解决方法,有解决方案的还请多多指教~

    更多相关内容
  • WPF常用控件,包括按钮、文本框、下拉框、GridData、树、滚动条等等都进行了精心的设计,拿来即用!里面包含有样式里所需的图标文件哦!
  • JHRS开发框架之公用组件WPF用户控件封装,这个系列的文章旨在记录工作中使用WPF开发新的医疗项目中,有感于必须统一掉一些规范上的事情,并且提高团队开发效率,遂折腾了这么一个半吊子的框架,这个标题WPF企业级...

    JHRS开发框架之公用组件WPF用户控件封装,这个系列的文章旨在记录工作中使用WPF开发新的医疗项目中,有感于必须统一掉一些规范上的事情,并且提高团队开发效率,遂折腾了这么一个半吊子的框架,这个标题WPF企业级开发框架搭建指南,2020从入门到放弃可能会唬住一些人,但看到这些零碎文字的朋友就凑和着看吧,如果能帮助到你,那也荣幸了。

    继上一篇介绍了怎样封装ViewModel的基类,但随着项目大了,一个功能点一个功能点的做,真的累,很多系统里面,在局部有很多相似的功能,数据展示几乎一样的,或许不一样的只是摆放的位置,显示的样式不同罢了;这种东西,一个功能一个功能的实现,那就有点朝着996的状态发展了;因此在JHRS框架中,也体现了懒人干活的思想,那就是能封装成控件的,坚决搞成一个控件,供大家享乐。

    JHRS开发框架之公用组件WPF用户控件封装

    JHRS开发框架之公用组件WPF用户控件封装

    当然,用户控件可以套在用户控件里面,一个拥有复杂功能的页面,可以由众多的用户控件组成,最终你会发现,用户控件封装得越优雅,做复杂的功能页面也不会很难了,只需要像搭积木那样,把控件丢上去,数据绑定上就完事了,最后如果要调整样式,稍微调整下就OK了。

    WPF用户控件封装

    因为框架中引入了Prism将各子系统模块化了,所以我们在WPF用户控件封装的时候,分为两种情况,一种是封装整个系统公用的用户控件,另外一种是各子模块自己的用户控件;整个系统公用的用户控件,需要保持着高扩展性,灵活性,即使后期对该控件增加功能,也要尽量做到不影响已经使用该控件的页面(Page),还需要让使用的页面可以灵活的设置一些属性以满足不同页面(Page)的功能需求。

    在框架中只封装了3个基本的用户控件,动态列的DataGrid,可调接口的Combobox,动态分页表格。

    JHRS开发框架动态列的DataGrid

    大部分管理系统,都离不开表格展示数据,而WPF项目中,基本上都会使用DataGrid来展示数据;熟悉WPF开发的朋友都知道,如果手工撸一个表格,那代码贼烦人,需要一个列一个列的写代码并绑定数据;而在JHRS框架中提供的思路是基于注解的方式(自定义BindDescriptionAttribute类用于描述每列)动态生成每一列数据并自动绑定数据,对于复杂的列,如某一列里面展示为下拉框(ComoboBox)或者更复杂的展示,只需要在资源(Resources)里面定义DataTemplate即可,然后动态加载就可以了。对于最每一行的操作列,也是一样的套路。

    动态列的DataGrid封装思路是:编写一个DataGridEx类,继承自DataGrid类,在DataGridEx类中,需要定义一个依赖属性我们称为DataSource,用它来绑定数据,然后在DataSourceProperty的回调函数里面把DataSource赋值给原本的 ItemSource属性,最后重写OnInitialized方法,将数据源传入DataGrid的扩展方法GenerateColumns动态生成列就完成了WPF用户控件封装,详见下方代码。

    DataGridEx类源码

    /// <summary>
        /// 輕量級的DataGrid擴展
        /// </summary>
        public class DataGridEx : DataGrid
        {
            /// <summary>
            /// 構造函數
            /// </summary>
            public DataGridEx()
            {
                this.AutoGenerateColumns = false;
                this.Loaded += DataGridEx_Loaded;
                this.LoadingRow += PagingDataList_LoadingRow;
            }
    
            /// <summary>
            /// 给表格添加样式
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void DataGridEx_Loaded(object sender, RoutedEventArgs e)
            {
                this.CanUserAddRows = false;
            }
    
            /// <summary>
            /// 生成序号
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void PagingDataList_LoadingRow(object sender, DataGridRowEventArgs e)
            {
                if (EnableRowNumber)
                    //需要分页
                    e.Row.Header = e.Row.GetIndex() + 1;
            }
    
            /// <summary>
            /// 操作列key
            /// </summary>
            public string OperatingKey { get; set; } = string.Empty;
            /// <summary>
            /// 操作列的宽度
            /// </summary>
            public DataGridLength OperationWidth { get; set; }
    
            /// <summary>
            /// 是否启用序号
            /// </summary>
            public bool EnableRowNumber { get; set; } = true;
    
            /// <summary>
            /// 禁止显示的列
            /// </summary>
            public string DisableCloumn { get; set; }
    
            public IEnumerable<object> DataSource
            {
                get { return (IEnumerable<object>)GetValue(DataSourceProperty); }
                set { SetValue(DataSourceProperty, value); }
            }
    
            private bool IsGenerateColumns = false;
            // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DataSourceProperty =
                DependencyProperty.Register("DataSource", typeof(IEnumerable<object>), typeof(DataGridEx), new PropertyMetadata((d, e) =>
                {
                    DataGridEx u = d as DataGridEx;
                    u.ItemsSource = u.DataSource;
    
                    if (u.IsGenerateColumns || u.DataSource == null || u.DataSource.Count() == 0) return;
                    var index = 0;
                    if (u.EnableRowNumber)
                    {
                        var acolumn = new DataGridTextColumn
                        {
                            Header = "序号",
                            Width = new DataGridLength(50),
                            Binding = new Binding("Header") { RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridRow), 1) }
                        };
                        u.Columns.Insert(0, acolumn);
                        index++;
                    }
                    u.GenerateColumns(index, u.ItemsSource, u.OperatingKey, u.OperationWidth);
                    u.IsGenerateColumns = true;
    
                }));
    
    
            //protected override void OnInitialized(EventArgs e)
            //{
            //    if (IsGenerateColumns || ItemsSource == null) return;
            //    var index = 0;
            //    if (EnableRowNumber)
            //    {
            //        var acolumn = new DataGridTextColumn
            //        {
            //            Header = "序号",
            //            Width = new DataGridLength(50),
            //            Binding = new Binding("Header") { RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridRow), 1) }
            //        };
            //        this.Columns.Insert(0, acolumn);
            //        index++;
            //    }
            //    this.GenerateColumns(index, ItemsSource, OperatingKey, OperationWidth);
            //    IsGenerateColumns = true;
            //}
        }

    以上的基本上是完整的源码,github是参见这里

    DataGridExtensions扩展类源码

    /// <summary>
        /// DataGrid扩展方法
        /// </summary>
        public static class DataGridExtensions
        {
            /// <summary>
            /// 动态生成列
            /// </summary>
            /// <param name="dataGrid">DataGrid控件实例</param>
            /// <param name="index">列插入位置</param>
            /// <param name="data">数据源</param>
            /// <param name="operationKey">操作列资源</param>
            /// <param name="operationWidth">操作列宽度</param>
            public static void GenerateColumns(this DataGrid dataGrid, int index, object data, string operationKey, DataGridLength operationWidth)
            {
                IList<BindDescriptionAttribute> list = GetColumns(data);
                //Window win = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
                //Page page = win.GetChildObject<Page>("page");
                //if (page == null) throw new Exception("未獲取到當前窗口名稱爲page的(Page)頁面對象,原因:沒有爲Page設置Name,且名稱必須爲【page】!");
    
                Page page = GetParentObject<Page>(dataGrid, "page");
    
                for (int i = 0; i < list.Count; i++)
                {
                    switch (list[i].ShowAs)
                    {
                        case ShowScheme.普通文本:
                            dataGrid.Columns.Insert(i + index, new DataGridTextColumn
                            {
                                Header = list[i].HeaderName,
                                Binding = new Binding(list[i].PropertyName),
                                Width = list[i].Width
                            });
                            break;
                        case ShowScheme.自定义:
                            if (page.FindResource(list[i].ResourceKey) != null)
                            {
                                DataGridTemplateColumn val = new DataGridTemplateColumn();
                                val.Header = list[i].HeaderName;
                                val.Width = list[i].Width;
                                val.CellTemplate = page.FindResource(list[i].ResourceKey) as DataTemplate;
                                dataGrid.Columns.Insert(i + index, val);
                            }
                            break;
                    }
                }
                if (!string.IsNullOrWhiteSpace(operationKey) && page != null)
                {
                    var resource = page.FindResource(operationKey);
                    if (resource!=null)
                    {
                       
                        var col = new DataGridTemplateColumn() { Header = "操作", Width = operationWidth };
                        col.CellTemplate = resource as DataTemplate;
                        dataGrid.Columns.Add(col);
                    }
                }
            }
    
            /// <summary>
            /// 获取数据源对象到列的映射关系
            /// </summary>
            /// <param name="data"></param>
            /// <returns></returns>
            private static IList<BindDescriptionAttribute> GetColumns(object data)
            {
                List<BindDescriptionAttribute> list = new List<BindDescriptionAttribute>();
                var pros = data.GetType().GenericTypeArguments[0].GetProperties();
                foreach (var item in pros)
                {
                    var a = item.GetCustomAttribute<BindDescriptionAttribute>();
                    if (a != null) { a.PropertyName = item.Name; list.Add(a); }
                }
                return list.OrderBy(x => x.DisplayIndex).ToArray();
            }
    
            /// <summary>
            /// 查找父级控件
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="obj"></param>
            /// <param name="name"></param>
            /// <returns></returns>
            public static T GetParentObject<T>(DependencyObject obj, string name) where T : FrameworkElement
            {
                DependencyObject parent = VisualTreeHelper.GetParent(obj);
    
                while (parent != null)
                {
                    if (parent is T && (((T)parent).Name == name | string.IsNullOrEmpty(name)))
                    {
                        return (T)parent;
                    }
    
                    parent = VisualTreeHelper.GetParent(parent);
                }
    
                return null;
            }
        }

    完整的参见这里

    BindDescriptionAttribute注解类

    在调用web api从服务器端返回的数据中,需要在本地的WPF项目定义相关的实体类,并且在实体类的属性上标记绑定描述类(BindDescriptionAttribute),这个类直接描述了展面如何展示(一般用DataGrid,可按此思路扩展不规则表单),这也是WPF用户控件封装之前的准备工作。

    /// <summary>
        /// DataGrid绑定数据源描述
        /// </summary>
        public class BindDescriptionAttribute : Attribute
        {
            /// <summary>
            /// 列名
            /// </summary>
            public string HeaderName { get; set; }
    
            /// <summary>
            /// 显示为
            /// </summary>
            public ShowScheme ShowAs { get; set; }
    
            /// <summary>
            /// 显示顺序
            /// </summary>
            public int DisplayIndex { get; set; }
    
            /// <summary>
            /// DataGrid列绑定属性名称
            /// </summary>
            public string PropertyName { get; set; }
    
            /// <summary>
            /// 应用内的容模板Key
            /// </summary>
            public string ResourceKey { get; set; }
    
            /// <summary>
            /// 列宽
            /// </summary>
            public DataGridLength Width { get; set; }
    
            /// <summary>
            /// 列宽ByGrid
            /// </summary>
            public GridLength CloumnWidth { get; set; }
    
    
            /// <summary>
            /// DataGrid绑定数据源描述
            /// </summary>
            /// <param name="headerName">列名</param>
            /// <param name="showAs">显示为</param>
            /// <param name="width">宽度</param>
            /// <param name="displayIndex">显示顺序</param>
            /// <param name="resourceKey">自定义列Key</param>
            public BindDescriptionAttribute(string headerName, ShowScheme showAs = ShowScheme.普通文本, string width = "Auto", int displayIndex = 0, string resourceKey = "")
            {
                HeaderName = headerName;
                DisplayIndex = displayIndex;
                ResourceKey = resourceKey;
                ShowAs = showAs;
                var convert = new DataGridLengthConverter();
                Width = (DataGridLength)convert.ConvertFrom(width);
                var gridCOnvert = new GridLengthConverter();
                CloumnWidth = (GridLength)gridCOnvert.ConvertFrom(width);
    
                if (showAs == ShowScheme.自定义 && string.IsNullOrWhiteSpace(resourceKey))
                    throw new ArgumentException($"自定义列时需要指定{nameof(resourceKey)}参数!");
            }
        }
    
        /// <summary>
        /// 展示方式
        /// </summary>
        public enum ShowScheme
        {
            普通文本 = 1,
            自定义 = 4
        }

    上方的枚举ShowScheme则描述了对应的列的显示方案,是该使用普通的文本还是加载数据模板(DataTemplate)。

    如何使用DataGridEx实现动态表格功能

    要使用自己扩展的动态DataGrid其实是跟使用常规的DataGrid是一样的,只是区别是绑定数据是使用DataSource属性而已,下面就是WPF用户控件封装之动态表格xaml,如下代码所示:

    <Page
        x:Class="JHRS.RegisterManagement.Views.RegisterList"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:prism="http://prismlibrary.com/"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:c="clr-namespace:JHRS.Core.Controls.Common;assembly=JHRS.Core"
        xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 
        prism:ViewModelLocator.AutoWireViewModel="True" 
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800"
        x:Name="page"
        Title="RegisterList" Background="White">
        
        <b:Interaction.Triggers>
            <b:EventTrigger EventName="Loaded" >
                <b:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=page}" />
            </b:EventTrigger>
        </b:Interaction.Triggers>
        <Grid x:Name="maskContainer">
            <c:DataGridEx DataSource="{Binding PageData}" IsReadOnly="True"/>
        </Grid>
    </Page>

    上面代中<c:DataGridEx DataSource=”{Binding PageData}” IsReadOnly=”True”/>这行就是WPF用户控件封装的动态表格绑定数据的用法,而PageData则是来自ViewModel定义的一个IEnumerable<object>属性,只需要在当前页面(Page)的ViewModel里面调用接口获取数据给PageData赋值就可以了,如下代码所示:

            /// <summary>
            /// 綁定分頁數據
            /// </summary>
            [WaitComplete]
            protected async override Task<object> BindPagingData()
            {
                List<Account> list = new List<Account>();
                for (int i = 0; i < 15; i++)
                {
                    list.Add(new Account
                    {
                        Name = "趙佳仁" + i,
                        RegTime = DateTime.Now.AddDays(i),
                        RoleName = "管理員" + i,
                        Title = "無職" + i,
                        UserID = 100 + i
                    });
                }
                PageData = list;
                await Task.Delay(200);
                return true;
            }

    而Account类则是这样定义的。

        public class Account
        {
            [BindDescription("用戶ID")]
            public int UserID { get; set; }
            [BindDescription("用戶名")]
            public string Name { get; set; }
            [BindDescription("註冊時間")]
            public DateTime RegTime { get; set; }
            [BindDescription("角色名穩")]
            public string RoleName { get; set; }
            [BindDescription("職級")]
            public string Title { get; set; }
        }

    完整的代码参见这里。下图是最终的效果:

    WPF用户控件封装

    WPF用户控件封装

    Combobox扩展控件

    原生的Combobox是WPF提供的下拉框控件,如果约定在整个系统里面,所有的下拉框控件默认项为请选择,如下图所示:

    WPF用户控件封装

    统一的给加上这个的话,在框架中是这样做的,先自定义一个BaseComboBox类,继承自ComboBox类,并在代码里面添加一个默认项,代码如下:

    using JHRS.Http;
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace JHRS.Core.Controls.Common
    {
        /// <summary>
        /// 下拉框控件基类
        /// </summary>
        public abstract class BaseComboBox : ComboBox
        {
            /// <summary>
            /// 下拉框数据源
            /// </summary>
            public IList Data
            {
                get { return (IList)GetValue(DataProperty); }
                set
                {
                    AddDefault(value);
                    SetValue(DataProperty, value);
                }
            }
    
            /// <summary>
            /// 已登录获取到Token客户端对象
            /// </summary>
            protected HttpClient AuthClient => AuthHttpClient.Instance;
    
            /// <summary>
            /// 服务器配置
            /// </summary>
            protected string BaseUrl => AuthHttpClient.Instance.BaseAddress!.ToString();
    
            // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DataProperty =
                DependencyProperty.Register("Data", typeof(IList), typeof(BaseComboBox), new PropertyMetadata(null, (d, e) =>
                {
                    BaseComboBox c = (BaseComboBox)d;
                    var list = e.NewValue as IList;
                    if (list != null)
                        c.AddDefault(list);
                    c.Data = list;
                    c.ItemsSource = list;
                }));
    
            /// <summary>
            /// 构造函数
            /// </summary>
            public BaseComboBox()
            {
                this.Initialized += OnInitialized;
            }
    
            /// <summary>
            /// 下拉框初始化事件,子类实现,可以加载各自数据。
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            protected abstract void OnInitialized(object sender, EventArgs e);
    
            private string DefaultSelectedValue = "-1";
            private string DefaultSelectedText = "—請選擇—";
    
            /// <summary>
            /// 添加默认项:请选择
            /// </summary>
            /// <param name="data"></param>
            private void AddDefault(IList data)
            {
                if (data == null || data.Count == 0) return;
                var pros = data[0].GetType().GetProperties();
                bool hasSelect = false;
                var s = pros.FirstOrDefault(x => x.Name == SelectedValuePath);
                var d = pros.FirstOrDefault(x => x.Name == DisplayMemberPath);
                if (s == null) throw new Exception("未給ComboBox指定SelectedValuePath屬性,注意:屬性區分大小寫!");
                if (d == null) throw new Exception("未给ComboBox指定DisplayMemberPath屬性,注意:屬性區分大小寫!");
                foreach (var item in data)
                {
                    if (s == d && (s.GetValue(item, null) + "") == DefaultSelectedText)
                    {
                        hasSelect = true;
                        break;
                    }
                    else if ((s.GetValue(item, null) + "") == DefaultSelectedValue && (d.GetValue(item, null) + "") == DefaultSelectedText)
                    {
                        hasSelect = true;
                        break;
                    }
                }
                if (hasSelect == false)
                {
                    var subType = data.GetType().GenericTypeArguments[0];
                    if (subType.Name.StartsWith("<>f__AnonymousType")) return;
                    var m = Activator.CreateInstance(subType);
                    if (s != d)
                    {
                        s.SetValue(m, Convert.ChangeType(DefaultSelectedValue, s.PropertyType), null);
                        d.SetValue(m, Convert.ChangeType(DefaultSelectedText, d.PropertyType), null);
                    }
                    else
                    {
                        d.SetValue(m, Convert.ChangeType(DefaultSelectedText, d.PropertyType), null);
                    }
                    data.Insert(0, m);
                }
            }
        }
    }

    上面的就是完整代码需要注意的是,在上面的代码中,处理匿名类型有Bug,并没有修复,强类型的绑定是会添加【—請選擇—】这个默认项的

    业务相关的ComboBox下拉框

    在实际项目里面,会有很多下拉框的数据源是需要调用接口获取的,将它封装后就可以避免在很多的功能页面(Page)或者控件里面再调接口来获取数据给ComboBox绑定数据,因此封装后直接拖过去用就完事了,这是WPF用户控件封装之下拉框。

    在框架里面封装了像科室,字典,通用业务状态的下拉框,这里只放一个科室的下拉框示例代码,因为科室是需要调接口获取的,下方注释掉的WPF用户控件封装代码就是真实项目中调用接口获取数据来绑定的代码。

    using JHRS.Core.Controls.Common;
    using JHRS.Core.Models;
    using System;
    using System.Collections.Generic;
    
    namespace JHRS.Core.Controls.DropDown
    {
        /// <summary>
        /// 科室下拉框
        /// </summary>
        public class DepartmentComboBox : BaseComboBox
      {
        /// <summary>
        /// 初始化科室數據,可調用接口獲取數據。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected override void OnInitialized(object sender, EventArgs e)
        {
          this.DisplayMemberPath = "Name";
          this.SelectedValuePath = "Id";
    
          //var response = await RestService.For<IDepartmentApi>(AuthHttpClient.Instance).GetAll();
          //if (response.Succeeded)
          //{
          //  Data = response.Data as IList;
          //}
    
          List<DepartmentOutputDto> list = new List<DepartmentOutputDto>();
          for (int i = 0; i < 20; i++)
          {
            list.Add(new DepartmentOutputDto
            {
              Id = i + 1,
              Name = $"測試科室{i + 1}"
            });
          }
          base.Data = list;
        }
      }
    
    }

    封装后下拉框怎样使用

    如下图所示一样,在演示框架中,WPF用户控件封装之后的控件是直接将其拖到用户控件相关位置,然后绑定你需要获取的值即可,使用的地方不需要关注科室的数据从哪儿来的,你只需要知道你用什么属性取接收选中的值即可。

    WPF用户控件封装

    以上就是使用的方法,接下来看看如何封装分页表格。

    动态分页表格

    每个系统里面分页表格是大头,或者说是比较复杂的功能,而在框架里面是将表格和分页控件封装到一起形成一个用户控件,在需要使用的地方,也是直接拖过去,并调用分页接口获取数据绑定即可;WPF用户控件封装表格的每一列展示什么数据,也是采用最上面介绍的最基础的动态表格思想解决的。

    分页表格控件XAML代码

    <UserControl x:Class="JHRS.Core.Controls.DataGrids.PagingDataGrid" 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:hc="https://handyorg.github.io/handycontrol" 
                 xmlns:local="clr-namespace:JHRS.Core.Controls.DataGrids" 
                 Loaded="UserControl_Loaded">
        <Grid Name="ucDataGrid">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="5"/>
                <RowDefinition Height="30"/>
            </Grid.RowDefinitions>
            <DataGrid  x:Name="pagingDataList" Grid.Row="0" IsReadOnly="True"
                      ItemsSource="{Binding PageData}" CanUserAddRows="False" SelectionMode="Single" 
                      LoadingRow="pagingDataList_LoadingRow">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding Header, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}, Mode=FindAncestor}}"  CanUserSort="False" Header="序号" IsReadOnly="True" Width="40"/>
                    <DataGridTemplateColumn Width="40" x:Name="isCheckbox">
                        <DataGridTemplateColumn.Header>
                            <CheckBox Click="CheckBox_Click"></CheckBox>
                        </DataGridTemplateColumn.Header>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox Click="chkItem_Click" x:Name="chkItem" VerticalAlignment="Center" HorizontalAlignment="Center"></CheckBox>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
            <hc:Pagination x:Name="ucPagination" Grid.Row="2" HorizontalAlignment="Right"  MaxPageCount="{Binding PagingData.MaxPageCount}" PageIndex="{Binding PagingData.PageIndex, Mode=TwoWay}">
                <b:Interaction.Triggers>
                    <b:EventTrigger EventName="PageUpdated" >
                        <b:InvokeCommandAction Command="{Binding ChangePageIndexCommand}"/>
                    </b:EventTrigger>
                </b:Interaction.Triggers>
            </hc:Pagination>
        </Grid>
    </UserControl>

    在这个WPF用户控件封装的xaml代码中,主要放了两个控件,一个DataGrid表格控件,一个Pagination分页控件。后台的C#代码如下:

    using JHRS.Core.Extensions;
    using JHRS.Filter;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace JHRS.Core.Controls.DataGrids
    {
        /// <summary>
        /// PagingDataGrid.xaml 的交互逻辑
        /// </summary>
        public partial class PagingDataGrid : UserControl
        {
            public PagingDataGrid()
            {
                InitializeComponent();
                pagingDataList.AutoGenerateColumns = false;
            }
    
            /// <summary>
            /// 生成序号
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void pagingDataList_LoadingRow(object sender, DataGridRowEventArgs e)
            {
                if (EnablePagination)
                    //需要分页
                    e.Row.Header = (PagingData.PageIndex - 1) * PagingData.PageSize + e.Row.GetIndex() + 1;
                else
                    //不需要分页
                    e.Row.Header = e.Row.GetIndex() + 1;
            }
    
            /// <summary>
            /// 表格数据源
            /// </summary>
            public IEnumerable<object> PageData
            {
                get { return (IEnumerable<object>)GetValue(PageDataProperty); }
                set { SetValue(PageDataProperty, value); }
            }
    
            //是否已经生成了列并建立了绑定关系 
            private bool IsGenerateColumns = false;
            // Using a DependencyProperty as the backing store for PageData.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty PageDataProperty =
                DependencyProperty.Register("PageData", typeof(IEnumerable<object>), typeof(PagingDataGrid), new PropertyMetadata((d, e) =>
                {
                    PagingDataGrid pagingDataGrid = d as PagingDataGrid;
                    if (pagingDataGrid.IsGenerateColumns) return;
                    int num = 0;
                    if (pagingDataGrid.EnableRowNumber) num++;
    
                    if (pagingDataGrid.EnableCheckBoxColumn) num++;
    
                    pagingDataGrid.pagingDataList.GenerateColumns(num, e.NewValue, pagingDataGrid.OperatingKey, pagingDataGrid.OperatingWidth);
                    pagingDataGrid.IsGenerateColumns = true;
                }));
    
    
            /// <summary>
            /// 分页控件数据源
            /// </summary>
            public PagingData PagingData
            {
                get { return (PagingData)GetValue(PagingDataProperty); }
                set { SetValue(PagingDataProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for PagingData.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty PagingDataProperty =
                DependencyProperty.Register("PagingData", typeof(PagingData), typeof(PagingDataGrid));
    
            /// <summary>
            /// 是否启用分页功能
            /// </summary>
            public bool EnablePagination { get; set; } = true;
    
            /// <summary>
            /// 是否启用序号
            /// </summary>
            public bool EnableRowNumber { get; set; } = true;
    
            /// <summary>
            /// 是否复选框列
            /// </summary>
            public bool EnableCheckBoxColumn { get; set; } = false;
    
            /// <summary>
            /// 复选框列是否启用全选功能
            /// </summary>
            public bool EnableSelectAll { get; set; } = false;
    
            /// <summary>
            /// 操作列的Key
            /// </summary>
            public string OperatingKey { get; set; }
    
            /// <summary>
            /// 操作列宽
            /// </summary>
            public DataGridLength OperatingWidth { get; set; }
    
            /// <summary>
            /// 当前选中数据
            /// </summary>
            public IEnumerable<object> CheckedList
            {
                get { return (IEnumerable<object>)GetValue(SelectedListProperty); }
                set { SetValue(SelectedListProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for SelectedList.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty SelectedListProperty =
                DependencyProperty.Register("CheckedList", typeof(IEnumerable<object>), typeof(PagingDataGrid),
                new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
    
    
            /// <summary>
            /// 初始化表格行为
            /// </summary>
            private void InintBehavior()
            {
                if (!EnablePagination) ucDataGrid.Children.Remove(ucPagination);
                if (!EnableRowNumber) pagingDataList.Columns.Remove(pagingDataList.Columns.FirstOrDefault(x => x.Header.ToString() == "序号"));
    
                if (!EnableCheckBoxColumn) pagingDataList.Columns.Remove(isCheckbox);
                if (!EnableSelectAll) isCheckbox.Header = "选择";
            }
    
            /// <summary>
            /// 用户控件初始化
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void UserControl_Loaded(object sender, RoutedEventArgs e)
            {
                InintBehavior();
            }
    
            /// <summary>
            /// 复选框全选事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void CheckBox_Click(object sender, RoutedEventArgs e)
            {
                var c = sender as CheckBox;
                CheckedAll(pagingDataList, c.IsChecked);
                CheckedList = GetSelected();
            }
    
            /// <summary>
            /// 全选
            /// </summary>
            /// <param name="parent"></param>
            /// <param name="isChecked"></param>
            private void CheckedAll(DependencyObject parent, bool? isChecked)
            {
                int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < numVisuals; i++)
                {
                    DependencyObject v = VisualTreeHelper.GetChild(parent, i);
                    CheckBox child = v as CheckBox;
    
                    if (child == null)
                    {
                        CheckedAll(v, isChecked);
                    }
                    else
                    {
                        child.IsChecked = isChecked;
                        break;
                    }
                }
            }
    
            /// <summary>
            /// 获取所有选中项
            /// </summary>
            /// <returns></returns>
            private List<object> GetSelected()
            {
                List<object> list = new List<object>();
                foreach (var item in pagingDataList.ItemsSource)
                {
                    var m = isCheckbox.GetCellContent(item);
                    var c = m.GetChildObject<CheckBox>("chkItem");
                    if (c != null && c.IsChecked == true)
                    {
                        list.Add(item);
                    }
                }
                return list;
            }
    
            /// <summary>
            /// 单击选中事件
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void chkItem_Click(object sender, RoutedEventArgs e)
            {
                CheckedList = GetSelected();
            }
        }
    }

    如何使用动态分页表格

    在需要使用的页面(Page)或者控件里面,将WPF用户控件封装后的控件拖进来就可以了,完整的xaml代码如下

    <Page x:Class="JHRS.OutpatientSystem.Views.Reservation" 
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
          xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
          xmlns:local="clr-namespace:JHRS.OutpatientSystem.Views" 
          xmlns:prism="http://prismlibrary.com/" 
          xmlns:b="http://schemas.microsoft.com/xaml/behaviors" 
          prism:ViewModelLocator.AutoWireViewModel="True" 
          xmlns:f="clr-namespace:JHRS.Core.Controls.Layouts;assembly=JHRS.Core" 
          xmlns:p="clr-namespace:JHRS.Core.Controls.DataGrids;assembly=JHRS.Core" 
          xmlns:c="clr-namespace:JHRS.Core.Controls.DropDown;assembly=JHRS.Core" 
          x:Name="page" 
          Title="Reservation" Background="#FFFFFFFF">
        <b:Interaction.Triggers>
            <b:EventTrigger EventName="Loaded" >
                <b:InvokeCommandAction Command="{Binding LoadedCommand}" CommandParameter="{Binding ElementName=page}" />
            </b:EventTrigger>
        </b:Interaction.Triggers>
        <Page.Resources>
            <DataTemplate x:Key="Status">
                <c:StatusComboBox Name="cboStatus" SelectedValue="{Binding Status, Mode=TwoWay, UpdateSourceTrigger=Explicit,Converter={StaticResource EnumToIntConverter}}">
                    <b:Interaction.Triggers>
                        <b:EventTrigger EventName="SelectionChanged" >
                            <b:InvokeCommandAction Command="{Binding DataContext.SelectionChangedCommand,RelativeSource={RelativeSource AncestorType=Page}}" CommandParameter="{Binding ElementName=cboStatus}"/>
                        </b:EventTrigger>
                    </b:Interaction.Triggers>
                </c:StatusComboBox>
            </DataTemplate>
            <DataTemplate x:Key="OperationKey">
                <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
                    <Button Name="btnEdit" Content="編輯" Background="#00FFFFFF" Style="{StaticResource MaterialDesignOutlinedButton}" Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource AncestorType=Page}}" CommandParameter="{Binding Path=DataContext, ElementName=btnEdit}" />
                    <Button Name="btnView" Content="詳情" Margin="10,0,0,0" ToolTip="详情" Command="{Binding DataContext.ViewDetailsCommand, RelativeSource={RelativeSource AncestorType=Page}}" CommandParameter="{Binding Path=DataContext, ElementName=btnView}" />
                </StackPanel>
            </DataTemplate>
        </Page.Resources>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="50" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Grid VerticalAlignment="Top">
                <f:FunctionArea AddButtonText="新增預約" />
            </Grid>
            <Grid Name="maskContainer" Row="1">
                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="5" />
                    <RowDefinition Height="30" />
                </Grid.RowDefinitions>
                <p:PagingDataGrid Name="ucDataGrid" OperatingKey="OperationKey" OperatingWidth="150*" EnableSelectAll="True" PageData="{Binding PageData}" PagingData="{Binding PagingData}" />
            </Grid>
        </Grid>
    </Page>

    上面代码中<p:PagingDataGrid Name=”ucDataGrid” OperatingKey=”OperationKey” OperatingWidth=”150*” EnableSelectAll=”True” PageData=”{Binding PageData}” PagingData=”{Binding PagingData}” />就是应用动态分页表格的方法,注意绑定数据是你封装的用户控件的PageData依赖属性,而里面绑定的数据源PageData则是ViewModel基类定义的分页数据属性,需要在各子类的ViewModel里面调用接口赋值,如下代码所示:

            /// <summary>
            /// 綁定分頁數據
            /// </summary>
            [WaitComplete]
            protected async override Task<object> BindPagingData()
            {
                var request = this.GetQueryRules(Query);
                var response = await RestService.For<IReservationApi>(AuthClient).GetPageingData(request);
                if (response.Succeeded)
                {
                    PageData = response.Data.Rows;
                    this.PagingData.Total = response.Data.Total;
                }
                return response;
            }

    总结一下

    合理的进行WPF用户控件封装,可以减少很多重复的代码,本文阐述了怎样封装用户控件的思想,实际项目中,可以结合团队情况和项目状况来封装,总之身处IT江湖,名正言顺的偷偷懒也是向老板多要工资的理由,因为你干活又快又好,哪个包工头不喜欢呢?

    下一篇将介绍一下在团队开发中,关于目录文件遵循的一些原则,如果有更好的方式,也欢迎大家提出来。

    本系列相关阅读

    1. WPF企业级开发框架搭建指南(启示录)
    2. JHRS开发框架之基础类库
    3. JHRS开发框架之第三方框架选型
    4. JHRS开发框架之WPF调用Web API封装
    5. JHRS开发框架之客户端入口项目
    6. JHRS开发框架之各子系统如何整合
    7. JHRS开发框架之怎样设计合理的ViewModel基类
    8. JHRS开发框架之公用组件用户控件的封装
    9. JHRS开发框架之建议遵循的一些建目录文件原则
    10. JHRS开发框架之WPF数据验证
    11. JHRS开发框架之ViewModel相互传参和弹框回传参的解决办法
    12. JHRS开发框架之踩坑记(终章)
    展开全文
  • WPF-ControlBase OverView 动画封装 属性表单 消息对话 在WPF中应用MVC 其他功能说明 支持
  • wpf 自定义 封装控件
  • WPF-自定义控件

    2017-05-18 18:24:40
    资源中包括自己写的控件和修改别人的集成到自己的控件。主要有:温度计控件、Win8转圈等待控件、车速仪表控件、微信圆球摆动控件、加载等待转圈控件等包括源码,欢迎下载
  • 刚开始用插件式开发练习项目时添加新项时却不能添加WPF窗体,只有一个用户控件能添加。 后来发现是添加新建项目时添加的是类库就不行,改成添加WPF应用程序时可以正常添加。 但这不是一个好的解决方案,不符合...

    参考:https://blog.csdn.net/xionglifei2014/article/details/80782753

    刚开始用插件式开发练习项目时添加新项时却不能添加WPF窗体,只有一个用户控件能添加。

    后来发现是添加新建项目时添加的是类库就不行,改成添加WPF应用程序时可以正常添加。

     

    但这不是一个好的解决方案,不符合插件式开发(需要的是dll)添加WPF应用程序Visual Studio会把它编译成exe,类库则编译成dll。

     

    好的解决方案是添加一个Visual Studio模板:

    1、新建一个WPF应用程序

     

    你可以随便起一个名字。

    2、导出模板

    选择文件导出模板

     

    3、选择导出模板的类型为项模板(Ⅰ)

    可以看看两种模板的区别。

     

    4、选择要导出的模板为MainWindow.xaml

     

    5、我没有选择要添加的引用

     

    6、可以更改模板名称,选择自动将母版导入Visual Studio(A)

     

    7、我们来创建一个类库试试

     

    8、向类库中添加新项目

    9、第一个即是我们的模板(WPF窗口)

     

    好了,完成,终于可以在类库中添加WPF窗口了。

    最后只需将DLL文件引用即可使用其内容。

    eg:我将提示框(WPF窗口)分装到DLL中,如有项目需要,引用传值即可

     

    源码路径:https://pan.baidu.com/s/1gIIC8RqNACq8FW9_ve2bhA

     

    转载于:https://www.cnblogs.com/StitchWang/p/9578725.html

    展开全文
  • c# wpf分页控件

    2019-06-03 17:24:42
    c# wpf分页控件,支持多选,自定义样式,一键引用,方便快捷
  • 写了个通用的用户控件,用于登录界面复制,包含用户名、密码、登录按钮。点击事件将数据传输到引用界面。直接上图: 将这三者,甚至更多的,封装到一个UClogin当中,并给出一个LoginClick事件进行触发。 后台...

    写了个通用的用户控件,用于登录界面复制,包含用户名、密码、登录按钮。点击事件将数据传输到引用界面。直接上图:

     将这三者,甚至更多的,封装到一个UClogin当中,并给出一个LoginClick事件进行触发。

    后台事件代码:

     private void LoginClick_Click(object sender, EventArgs e)
            {
                LoginEventArgs args = e as LoginEventArgs;
                MessageBox.Show("账户:" + args.UserName + ",密码:" + args.Password);
            }

    这里拿到用户名和密码以后,自己就可以去判断逻辑进行跳转了。

    用户控件相关:

    用户控件后台代码:

       public partial class UCLogin : UserControl
        {
            public UCLogin()
            {
                InitializeComponent();
            }
    
            public delegate void LonginEventHandler(object sender, EventArgs e);
            public event LonginEventHandler LoginClick;
    
            private void btnLogin_Click(object sender, RoutedEventArgs e)
            {
                LoginClick?.Invoke(sender, new LoginEventArgs(e.RoutedEvent, txtUser.Text, txtPassword.Password));
            }
        }

    界面就登录名、密码、登录按钮,需要其他的可以自己继续封装,加背景等。例如这样:

     

    运行点击效果如下:

     LoginEventArgs是自己封装的事件,为了挣点积分不容易。需要的可以下载下,技术牛的应该自己能推算出来这个事件的写法。

    完整链接

     

    展开全文
  • WPF常用用户控件样式,包括按钮、文本框、下拉框、GridData、树、滚动条等等都进行了精心的设计,拿来即用!里面包含有样式里所需的图标文件哦!
  • wpf自定义控件库,包含列表,按钮,文本框,滚动条,进度条,消息窗体,气泡组件等多种自定义控件样式。
  • wpf用户分页控件

    2018-10-11 12:30:53
    wpf用户分页控件封装好的wpf分页控件,直接引入项目使用。
  • WPF最小到系统托盘 让WPF应用最小到系统托盘?网上都是调用System.Windows.Forms.NotifyIcon来实现,感觉很不方便,这边提供一个封装好的,专门用于wpf的,使用很简单,看Demo一学就会
  • WPF自定义美化控件,用于界面的美化。可直接在提供的源码基础上开发出属于自己的一套控件库,便于后续系统开发等
  • wpf自定义控件回调

    2019-08-07 14:08:12
    控件页面定义 public delegate void DelReturnHandle(object sender, EventArgs e); public event DelReturnHandle UserControlDel; //在触发的事件里的写法,如果需要传值则将sender换成需要传的值 private ...
  • 项目中经常需要使用多选下拉交互的控件,于是自己封装了一个helper,用于选择状态的读取,当然还包括多选框样式,仅供参考学习
  • 一、创建自定义控件 1、控件后台交互类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows....
  • wpf自定义控件

    2020-12-12 19:02:29
    在学习wpf中,wpf中有许多已经定义好的控件供我们选择应用,当我需要定义一个带文字标识的输入框时,模板中自带的控件的默认下的效果,与我想要的有所差别,而解决这个问题在于自行定义模板中的样式,下面就以文本...
  • 首先,新建一个WPF自定义控件库项目 这里我们封装一个支持自己绘制形状的图片按钮,且支持图片和文字。 运行效果如下:(形状是我随便绘的) 将默认的CustomControl1.cs改成ImageButton.cs 这个...
  • WPF、通过xaml的设计模式,制作了电池的控件界面, 很好用的一个插件
  • wpf时间控件带时分秒

    2018-12-14 11:12:06
    wpf带时间控件带时分秒的显示,支持mvvm,源码中带封装好的类库和调用的demo,用起来十分方便
  • 一、目的:在开发中常用到的一些控件、窗体、样式、模板、动画等等的封装示例,整理了一些网上开源的源代码为后续开发提升效率; 二、示例: 1、窗体、按钮、输入控件 2、文本控件、勾选控件、下拉控件、...
  • 在使用WPF以前,动辄使用自定义控件几乎成了惯性思维,比如需要一个带图片的按钮,但在WPF中此类任务却不需要如此大费周章,因为控件可以嵌套使用以及可以为控件外观打造一套新的样式就可以了.是否需要我们来自定义控件,...
  • WPF中DataGrid控件

    2020-07-29 19:15:40
    看一下DataGrid的独特属性: ...CanUserReorderColumns:是否允许用户通过使用鼠标拖拽列标题,更改列的显示顺序 CanUserResizeColumns:是否允许用户通过鼠标更改列的宽度 CanUserResizeRows:是否允许
  • 自定义WPF控件封装成DLL

    千次阅读 2017-03-15 16:09:30
    打开VS2015 1.新建项目 在菜单栏——文件——新建——项目——选择 C# 类库项目(ClassLibrary)——确定 2.添加必要引用 ...3.添加自定义控件 在解决方案管理器里,项目上右键——添加新建项——用户
  • WPF 控件模板

    2022-02-16 09:38:53
    WPF 控件模板 WPF中每个控件都被设计为无外观的,这意味着我们可以通过一定的方式,完全重定义其可视化外观,而WPF也提供了这种改变外观的方式之一,我们称为模板。wpf的模板有多种方式,可以分为控件模板...
  • WPF中TreeView实现
  • 外观样式 <Style TargetType="{x:Type local:ToolTipButton}"> <Setter Property="Template"> <Setter.Value> ...ControlTemplate TargetType="{x:Type local:ToolTipButton}">...
  • 这里采用WPF引用开源的Vlc相关插件(重新编译)封装了一个简单的视频播放器控件,实现视频播放、暂停、停止、快进、慢进、视频条、声音条、最大化等功能。 实现效果: 1、相关插件及资源文件放在了网盘,地址:...
  • WPF 样式 Style 封装

    2022-01-12 13:41:53
    从上面截图可以看出有三个圆形的 Button , 他们的大小和鼠标悬停的效果一样,只是颜色各有不同,所以在实际的开发过程中最好是能够将样式模板封装起来,这样做减少了代码冗余,在开发过程中,如有相同的按钮样式实现...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 6,597
精华内容 2,638
关键字:

wpf封装用户控件