精华内容
下载资源
问答
  • 自定义表格控件

    2014-09-23 13:48:20
    继承自VC自带的CListCtrl,原有的代码不需要任何改变即可加入,可以轻易做出多种风格的CListCtrl,包括可编辑的表格,类似COMBOX的下拉列表,带图标的,更改背景颜色和前景颜色等,甚至有日期选项框,而且可以单独...
  • 自定义表格控件,博客:http://blog.csdn.net/zhumj_zhumj/article/details/78621564
  • 著名的自定义表格控件gridctrl使用实例;国外开源自定义控件; 广泛应用于mfc项目;轻量级表格控件,使用很方便快捷;
  • 随着人们对视觉的需求,基本组件已无法满足人们求新求异的要求,于是我们常常会自定义组件,用来实现更美观的UI界面,接下来将介绍Android如何自定义表格控件,感兴趣的朋友可以了解下,或许对你学习自定义控件有所...
  • Android 自定义表格控件

    万次阅读 2018-08-20 17:07:58
    tabview是一款开源表格控件,可以通过xml属性设置行列数、设置表格标题、内容以及表头,对每行可以做点击事件处理。 2.引入 ps:不知道为什么bintray服务器总是异常,所以使用gradle,总是需要添加一句话感觉不太...

    1.简介

    tabview是一款开源表格控件,可以通过xml属性设置行列数、设置表格标题、内容以及表头,对每行可以做点击事件处理。

    2.引入

    ps:不知道为什么bintray服务器总是异常,所以使用gradle,总是需要添加一句话感觉不太友好。

    maven :

    gradle:

    compile 'com.hlq:tableview:1.1.0'

    此外还需在项目根目录下的build.gradle中添加:

    3.使用

    xml布局中:

    <hlq.tablbeview.TableView
        app:rownum = "6"
        app:colnum = "4"
        android:id="@+id/tabview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    上述设置为6行4列的表格

    在java代码中:

    private String[] mlistHead={"id","姓名","学号","性别"};//声明表格表头
    private String[] mlistContent={"1","黄林晴","2014211617","男"};//对应内容

    然后设置监听事件、表格表头以及表格对应内容

    tableView.setTable(new OnTableClick() {
        @Override
        public void onTableClickListener(int row, int col) {
    
        }
    });
    tableView.setTableHead(mlistHead);
    tableView.setTableContent(mlistContent);

    效果如下:

    其他xml基本属性如下:(注意:只有下方列出来的可用,其他不可用,后续会更新)

    属性名称意义默认值
    rownum行数0
    colnum列数0
    head_is_show是否显示表格表头false
    headtext表头文字默认文字
    headheight表头高度80dp
    tablehead_height表格标题高度100dp
    tablecontent_height表格内容高度100dp

    比如我们设置显示表格表头,并设置标题名称

    <hlq.tablbeview.TableView
        app:rownum = "6"
        app:colnum = "4"
        app:head_is_show = "true"
        app:headtext="物联网141点名册"
        android:id="@+id/tabview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

    效果如下:

    开源源码:https://github.com/huanglinqing123/TableView

    定有不足之处,欢迎提bug和start,后面会加入列合并等更多属性支持,后续会持续维护更新。

    欢迎关注技术公众号,微信号搜索ColorfulCode 代码男人

    分享技术文章,投稿分享,不限技术种类,不限技术深度,让更多人因为分享而受益。

    展开全文
  • 这是PPC上面的自定义表格控件源代码,演示了如何通过
  • WPF自定义表格控件

    2017-06-10 17:07:21
    WPF自定义控件,动态添加、删除行,支持编辑,对外提供DataTable数据
  • 不能访问源代码(译注:因为商业目的)使得这非常令人沮丧,因此我想倒不如我写篇CodeProject文章,看看我是否可以拿出一个自定义解决方案。 因为网格比列表更加灵活,我决定实现一个可以一起分组的网格控件,正如...
  • 支持首列固定 左右滑动 自定义表格 ios gridview 表格 iphone
  • 在我看来,只有在一些定制化的地方需要做自定义View,如果你在Github上搜索自定义View或者XX控件你会找到很多不错...做表格控件的初衷是为了防止业务过度交叉,项目中需要做一个可以很多地方用到的表格功能,这个表格可

    在我看来,只有在一些定制化的地方需要做自定义View,如果你在Github上搜索自定义View或者XX控件你会找到很多不错的开源组件,而实际上,这些开源组件里面有很多功能,而这些功能不一定是开发者当时所需要的,如果贸然引入进去必然增加维护难度。

    最合适自己的才是最好的,这句话不仅仅用在开源组件合适,用在选择书上也合适,甚至可以用在任何选择场景上;不多不少,不增不减,刚刚合适,这一直是我的生活理念也是我的开发理念;

    做表格控件的初衷是为了防止业务过度交叉,项目中需要做一个可以很多地方用到的表格功能,这个表格可以静态显示,也可以动态刷新里面的数据。数据的来源是一个复杂对象,我并不希望我做的这部分功能影响到组员的开发,因此我觉得可以写一个自定义View来解决这个问题;

    先上效果图,没图没真相;
    在这里插入图片描述

    需求整理

    我们来理一下需求,我简单列一下:

    1. 一个表格控件;
    2. 支持表头和单元格分开定义;
    3. 支持自定义属性(边框线宽,表头高度,单元格高度,表头背景)
    4. 传入一个复杂对象list,就能刷新表格数据;
    5. 符合当前场景就行,不需要多高扩展度;

    编码实现

    由于功能比较简单,我这里就直接上代码了,首先是一个复杂对象,表格控件接收到这个对象后取里面的值进行绘制;对象我就随便写了,每个人的对象肯定是不一样的,我这里只是参考;

    package tableview.tableview.bean;
    
    public class IeNr5gBin {
        public float getMacThroughput() {
            return (float) (Math.random() * 10);
        }
    
        public float getPhyThroughput() {
            return (float) (Math.random() * 10);
        }
    
        public float getDlSdapThroughput() {
            return (float) (Math.random() * 10);
        }
    
        public float getUlSdapThroughput() {
            return (float) (Math.random() * 10);
        }
    
        public float getDlThroughput() {
            return (float) (Math.random() * 10);
        }
    
        public float getUlThroughput() {
            return (float) (Math.random() * 10);
        }
    
    
    }
    
    

    然后我们把表格的布局搞一下,分为表头和表格体;

    <?xml version="1.0" encoding="UTF-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/head_head"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <TableLayout
            android:id="@+id/table_head"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
        <TableLayout
            android:id="@+id/table_content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    

    布局好了之后,我们把要用到的自定义属性定义一下;自定义控件的自定义属性支持几种类型:

    • reference:参考某一资源ID
    • color:颜色值
    • boolean:布尔值
    • dimension:尺寸值
    • float:浮点值
    • integer:整型值
    • string:字符串
    • fraction:百分数
    • enum:枚举值
    • flag:位或运算
      .
      大家可以根据自己的需要定义,我这里只用了最基本的两种,在value文件夹下新建attr.xml(如果你有样式文件可以直接在里面添加),内容如下:
    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <declare-styleable name="LayerInfoTableView">
            <attr name="head_bg" format="color" />
            <attr name="border" format="dimension" />
            <attr name="head_height" format="dimension" />
            <attr name="content_height" format="dimension" />
        </declare-styleable>
    </resources>
    

    然后就是具体实现了,由于比较简单,我就只说一下我事先的步骤,具体大家可以看代码;

    1. 自定义控件继承布局;
    2. 在构造方法里面获取到布局文件中定义的属性并绘制基础View(表头);
    3. 暴露设置数据的方法,拿到数据后转换成表格相关的数据;
    4. 根据数据生成对应的行和列的View,填充到控件中;
    package tableview.tableview;
    
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.graphics.Canvas;
    import android.graphics.Color;
    import android.graphics.Paint;
    import android.text.TextUtils;
    import android.util.AttributeSet;
    import android.util.DisplayMetrics;
    import android.util.Log;
    import android.view.Gravity;
    import android.view.LayoutInflater;
    import android.view.ViewGroup;
    import android.widget.RelativeLayout;
    import android.widget.TableLayout;
    import android.widget.TableRow;
    import android.widget.TextView;
    
    import java.text.DecimalFormat;
    import java.util.ArrayList;
    import java.util.List;
    
    import tableview.tableview.bean.IeNr5gBin;
    
    
    /**
     * 支持显示各层速率信息的TableView,用法很简单,只需要传入一个IeBin对象,
     * 他就能根据对应制式将数据展示到表格中,
     * 更新数据使用updateData()方法
     */
    public class LayerInfoTableView extends RelativeLayout {
        private static final String TAG = "LayerInfoTableView";
    
        /**
         * xml中可配置的属性
         */
        private int head_bg;
        private int borderWidth;
        private int headHeight;
        private int contentHeight;
    
        private Context mContext;
        private final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT;
        private final int FILL_PARENT = ViewGroup.LayoutParams.MATCH_PARENT;
    
        private List<ColumnData> data;
    
        public LayerInfoTableView(Context context) {
            super(context);
            this.mContext = context;
            init(context, null);
        }
    
        public LayerInfoTableView(Context context, AttributeSet attrs) {
            super(context, attrs);
            this.mContext = context;
            init(context, attrs);
        }
    
        public LayerInfoTableView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            this.mContext = context;
            init(context, attrs);
        }
    
        private void init(Context context, AttributeSet attrs) {
            if (attrs != null) {
                TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.LayerInfoTableView);
                head_bg = typedArray.getColor(R.styleable.LayerInfoTableView_head_bg, getResources().getColor(android.R.color.white));
                headHeight = (int) typedArray.getDimension(R.styleable.LayerInfoTableView_head_height, 100);
                contentHeight = (int) typedArray.getDimension(R.styleable.LayerInfoTableView_content_height, 100);
                borderWidth = (int) typedArray.getDimension(R.styleable.LayerInfoTableView_border, 1);
                typedArray.recycle();
            }
    
            // 屏幕分辨率
            DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
            int screenW = displayMetrics.widthPixels;
            int screenH = displayMetrics.heightPixels;
    
            // 初始化表头
            LayoutInflater.from(mContext).inflate(R.layout.layout_layer_info, this);
            TableRow mTableRow = makeTableRows(true, "名称", "UL(kps)", "DL(kps)");
            TableLayout tableHeader = this.findViewById(R.id.table_head);
            tableHeader.setBackgroundColor(head_bg);
            tableHeader.setStretchAllColumns(true);
            tableHeader.addView(mTableRow, new TableLayout.LayoutParams(WRAP_CONTENT, FILL_PARENT));
    
            Log.d(TAG, "init layerInfoTableView complete,screenW=" + screenW + ",screenH=" + screenH);
        }
    
        public void setData(IeNr5gBin ieBin) {
            // 解析表格体数据
            data = parseTableContent(ieBin);
            // 设置数据
            initTableContent(data);
        }
    
        private List<ColumnData> parseTableContent(IeNr5gBin nr5gBin) {
            List<ColumnData> columnDataList = new ArrayList<>();
            if (nr5gBin == null) {
                return columnDataList;
            }
    
            float sdapDlRate = nr5gBin.getDlSdapThroughput();
            float sdapUlRate = nr5gBin.getUlSdapThroughput();
            columnDataList.add(new ColumnData("SDAP", sdapUlRate, sdapDlRate));
    
            float pdcpDlRate = nr5gBin.getDlThroughput();
            float pdcpUlRate = nr5gBin.getUlThroughput();
            columnDataList.add(new ColumnData("PDCP", pdcpUlRate, pdcpDlRate));
    
            float macDlRate = nr5gBin.getMacThroughput();
            float macUlRate = nr5gBin.getMacThroughput();
            columnDataList.add(new ColumnData("MAC", macUlRate, macDlRate));
    
            float phyDlRate = nr5gBin.getPhyThroughput();
            float phyUlRate = nr5gBin.getPhyThroughput();
            columnDataList.add(new ColumnData("PHY", phyUlRate, phyDlRate));
    
            float rlcDlRate = nr5gBin.getDlThroughput();
            float rlcUlRate = nr5gBin.getUlThroughput();
            columnDataList.add(new ColumnData("RLC", rlcUlRate, rlcDlRate));
            return columnDataList;
        }
    
        private void initTableContent(List<ColumnData> dataList) {
            LayoutInflater.from(mContext).inflate(R.layout.layout_layer_info, this);
            TableLayout tabContent = this.findViewById(R.id.table_content);
            tabContent.setStretchAllColumns(true);
            tabContent.removeAllViews();
    
            for (ColumnData columnData : dataList) {
                String name = columnData.name;
                String ulSpeed = floatToStr(columnData.ulRate);
                String dlSpeed = floatToStr(columnData.dlRate);
                TableRow tableRow = makeTableRows(false, name, ulSpeed, dlSpeed);
                tabContent.addView(tableRow, new TableLayout.LayoutParams(WRAP_CONTENT, FILL_PARENT));
            }
        }
    
        private TableRow makeTableRows(boolean isHead, String... otherRows) {
            int tCellW = getWidth() / otherRows.length;
            TableRow mTableRow = new TableRow(mContext);
            for (int i = 0; i < otherRows.length; i++) {
                TextView ulView = makeCellView(isHead, tCellW, otherRows[i]);
                mTableRow.addView(ulView, i);
            }
            return mTableRow;
        }
    
        private TextView makeCellView(boolean isHead, int cellWidth, String name) {
            TextView celView = new TextView(mContext);
            celView.setSingleLine(true);
            celView.setSelected(true);
            celView.setText(name);
            celView.setWidth(cellWidth);
            celView.setTextColor(Color.BLACK);
            celView.setGravity(Gravity.CENTER);
            celView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
            celView.setHeight(isHead ? headHeight : contentHeight);
            if (isHead) {
                celView.setBackgroundColor(head_bg);
            }
            return celView;
        }
    
        @Override
        protected void dispatchDraw(Canvas canvas) {
            if (data == null || data.size() == 0) {
                return;
            }
    
            int mCol = 3;
            int mRow = data.size();
            int cellWidth = getWidth() / mCol;
            Paint paint = new Paint();
            paint.setStrokeWidth(borderWidth);
            paint.setColor(Color.rgb(79, 129, 189));
            paint.setStyle(Paint.Style.STROKE);
    
            // 绘制header的边框
            canvas.drawRect(0, 0, getWidth(), headHeight, paint);
            // 画列分割线
            for (int i = 0; i < mCol + 1; i++) {
                int startX = cellWidth * i;
                canvas.drawLine(startX, 0, startX, getHeight(), paint);
            }
            // 画行分割线
            for (int j = 1; j < mRow + 1; j++) {
                int startY = contentHeight * j + headHeight;
                canvas.drawLine(0, startY, getWidth(), startY, paint);
            }
            super.dispatchDraw(canvas);
        }
    
        public String floatToStr(float f) {
            DecimalFormat df = new DecimalFormat("#.00");
            return df.format(f);
        }
    
        static class ColumnData {
            String name;
            float ulRate;
            float dlRate;
    
            public ColumnData(String name, float ulRate, float dlRate) {
                this.name = name;
                this.ulRate = ulRate;
                this.dlRate = dlRate;
            }
        }
    
    }
    
    

    到这里自定义控件做好了,接下来就是在界面中引用这个控件并编写逻辑代码控制控件刷新了;

    控件使用

    首先我们写一个布局文件,为了简单我直接新建了个module然后在主界面的布局文件中添加了这个控件,并设置了需要的属性;

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="tableview.tableview.MainActivity">
    
        <tableview.tableview.LayerInfoTableView
            android:id="@+id/tabview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="1dp"
            app:border="1dp"
            app:content_height="20dp"
            app:head_bg="@android:color/transparent"
            app:head_height="30dp"/>
    
    </LinearLayout>
    
    

    然后我们来写一些逻辑控制这个刷新;为了简单,我就用timer做一个定时器啦;

    package tableview.tableview;
    
    import android.os.Bundle;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import java.util.Timer;
    import java.util.TimerTask;
    
    import tableview.tableview.bean.IeNr5gBin;
    
    
    public class MainActivity extends AppCompatActivity {
    
        private LayerInfoTableView tableView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            tableView = findViewById(R.id.tabview);
            tableView.setData(new IeNr5gBin());
    
            refreshData();
        }
    
        private void refreshData() {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                public void run() {
                    refreshInUiThread();
                }
            }, 5000, 1000);
        }
    
        private void refreshInUiThread() {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("-------延迟5000毫秒,每1000毫秒执行一次--------");
                    tableView.setData(new IeNr5gBin());
                }
            });
        }
    
    }
    
    
    

    运行

    跑起来,看一下效果如何;
    在这里插入图片描述
    如果需要完整代码资源,可在我的csdn下载页下载;

    展开全文
  • 最近在项目开发中遇到一个小...我们希望根据设备类型能够自主添加/修改/删除属性,另一方面其他模块也会用到此功能,所以考虑做一个自定义控件,将增、删、改操作封装在控件内部,数据对外开放。 环境 版本 操作系统

    最近在项目开发中遇到一个小问题,我们的设备管理模块中有一项叫做“技术参数”,具体来说就是不同的设备具有不同的属性,而且属性的数量也不同。举个例子,桌子有长、宽、高、材质四个属性,日光灯有安装高度、额定功率两个属性。我们希望根据设备类型能够自主添加/修改/删除属性,另一方面其他模块也会用到此功能,所以考虑做一个自定义控件,将增、删、改操作封装在控件内部,数据对外开放。


    环境版本
    操作系统Windows 10
    编译器Visual Studio 2015 update3

    期望目标

    期望达到的效果如下图所示:
    这里写图片描述

    包含两列数据(属性名称和属性值),可以手动添加/删除行,同时支持编辑,对外提供一个数据集合(DataTable,Dictionary或List)。

    创建控件并添加依赖项属性

    在WPF项目里添加一个UserControl,命名为TableControl。我们希望这个控件的某个属性具有这样的特性:属性值发生变化时,控件的数据呈现立刻跟随变化;任意时刻访问控件的这个属性,都能保证属性值与呈现的数据保持一致。由此我们就需要一个自定义的依赖项属性,另外考虑到通用性,我们决定使用DataTable作为这个依赖项属性的数据类型。(创建自定义依赖项属性快捷键:输入propdp,按两次Tab键)。

        public partial class TableControl : UserControl
        {
            public TableControl()
            {
                InitializeComponent();
            }
    
    
            #region 自定义依赖项属性
    
            public DataTable DataSource
            {
                get { return (DataTable)GetValue(DataSourceProperty); }
                set { SetValue(DataSourceProperty, value); }
            }
    
            // Using a DependencyProperty as the backing store for DataSource.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty DataSourceProperty =
                DependencyProperty.Register("DataSource", typeof(DataTable), typeof(TableControl), new PropertyMetadata(new DataTable(), DataSourceChanged));
    
            private static void DataSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                TableControl control = d as TableControl;
                if (e.NewValue != e.OldValue)
                {
                    DataTable dt = e.NewValue as DataTable;
                }
            }
            #endregion
    
        }

    创建自定义依赖项属性DataSource后,又为其添加了一个属性改变事件DataSourceChanged,以确保属性值发生变化后能够进行相应的操作。

    修改控件布局

    WPF自带的DataGrid表格控件本身就支持增删改数据行,所以控件主体仍为DataGrid。要让DataGrid增加行,只需要将其CanUserAddRows属性设为true即可,但使用起来不那么方便,所以另外添加了一个按钮用来添加行。删除和编辑行均可以在DataGrid的模板列里实现,代码如下:

        <Grid>
            <StackPanel>
                <DataGrid HeadersVisibility="None" AutoGenerateColumns="False" CanUserAddRows="False" x:Name="dgData" GridLinesVisibility="Horizontal">
    
                    <DataGrid.Columns>
                        <DataGridTemplateColumn Width="3*">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock  Text="{Binding Path=ParamKey,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"></TextBlock>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                            <DataGridTemplateColumn.CellEditingTemplate>
                                <DataTemplate>
                                    <TextBox  Text="{Binding Path=ParamKey,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,TargetNullValue=请输入}"></TextBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellEditingTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Width="10">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock Text=":"></TextBlock>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Width="3*">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock  Text="{Binding Path=ParamValue,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"></TextBlock>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                            <DataGridTemplateColumn.CellEditingTemplate>
                                <DataTemplate>
                                    <TextBox  Text="{Binding Path=ParamValue,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged,TargetNullValue=请输入}"></TextBox>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellEditingTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTemplateColumn Width="*">
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <Button Click="btnDel_Click">
                                        <Button.Content>
                                            <Border Width="32" Height="32" CornerRadius="16" Background="CornflowerBlue" VerticalAlignment="Center" HorizontalAlignment="Center">
                                                <Path Data="M0 0L22 0" Stroke="WhiteSmoke" StrokeThickness="4" VerticalAlignment="Center" HorizontalAlignment="Center"></Path>
                                            </Border>
                                        </Button.Content>
                                    </Button>
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                    </DataGrid.Columns>
                </DataGrid>
                <Grid Width="35">
                    <Button x:Name="btnAdd" Click="btnAdd_Click">
                        <Button.Content>
                            <Border Width="32" Height="32" CornerRadius="16" Background="CornflowerBlue" VerticalAlignment="Center" HorizontalAlignment="Center">
                                <Path Data="M0 11L22 11M11 0L11 22" Stroke="WhiteSmoke" StrokeThickness="4" VerticalAlignment="Center" HorizontalAlignment="Center"></Path>
                            </Border>
                        </Button.Content>
                    </Button>
                </Grid>
            </StackPanel>    
        </Grid>
    

    数据处理

    在数据处理上主要应用了WPF的双向绑定模式。控件初始化时就为DataGrid进行数据绑定。添加行时,创建一个与当前数据源具有相同结构的DataRow,将其追加到数据源上,重新进行数据绑定。由于采用了双向绑定,在页面上进行修改操作时,数据源也会随之发生变化,这样后台数据源和前台页面展示能始终保持一致,修改后的代码如下:

        public partial class TableControl : UserControl
        {
            private DataTable _dt = new DataTable();
            public TableControl()
            {
                InitializeComponent();
                _dt.Columns.Add(new DataColumn("ParamKey", typeof(string)));
                _dt.Columns.Add(new DataColumn("ParamValue", typeof(string)));
                this.dgData.ItemsSource = null;
                this.dgData.ItemsSource = _dt.DefaultView;
            }
    
    
            #region 自定义依赖项属性
    
            /// <summary>
            /// 数据源
            /// </summary>
            public DataTable DataSource
            {
                get { return ((DataView)this.dgData.ItemsSource).Table; }
                set { SetValue(DataSourceProperty, value); }
            }
    
            public static readonly DependencyProperty DataSourceProperty =
                DependencyProperty.Register("DataSource", typeof(DataTable), typeof(TableControl), new PropertyMetadata(new DataTable(), DataSourceChanged));
    
    
            private static void DataSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                TableControl control = d as TableControl;
                if (e.NewValue != e.OldValue)
                {
                    DataTable dt = e.NewValue as DataTable;
                    control._dt = dt;
                    control.dgData.ItemsSource = null;
                    control.dgData.ItemsSource = control._dt.DefaultView;
                }
            }
    
           #endregion
    
            /// <summary>
            /// 删除行
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnDel_Click(object sender, RoutedEventArgs e)
            {
                ((DataRowView)this.dgData.SelectedItem).Row.Delete();
            }
    
            /// <summary>
            /// 添加行
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnAdd_Click(object sender, RoutedEventArgs e)
            {
                _dt = ((DataView)this.dgData.ItemsSource).Table;
                DataRow dr = _dt.NewRow();
                _dt.Rows.Add(dr);
                this.dgData.ItemsSource = _dt.DefaultView;
            }
    
        }

    改动主要有四处:
    1.中间变量_dt
    创建了一个DataTable类型的局部变量_dt作为中间变量,用于数据初始化和数据绑定:

    private DataTable _dt = new DataTable();
    
    _dt.Columns.Add(new DataColumn("ParamKey", typeof(string)));
    _dt.Columns.Add(new DataColumn("ParamValue", typeof(string)));
    this.dgData.ItemsSource = null;
    this.dgData.ItemsSource = _dt.DefaultView;

    2.DataSource的返回值
    由于使用了双向绑定,我们想要的数据就在DataGrid的数据源里,将其返回即可:

    get { return ((DataView)this.dgData.ItemsSource).Table; }

    3.删除行

    ((DataRowView)this.dgData.SelectedItem).Row.Delete();

    进行删除行操作时,这段代码获取选择的DataRowView对象,查找到相应的DataRow对象,并使用Delete()方法将其标识为即将删除。这时可以看到删除的DataRow对象从列表中消失了,但实际上它仍位于DataTable.Rows集合中。原因是DataView中的默认过滤设置隐藏了所有已删除的记录(只是将其标识为删除,但并未真正删除)。这也是官方推荐使用的方法。
    另外一种方式就会导致选择的DataRowView对象被真正删除,代码如下,仅作参考,不建议使用:

    _dt.Rows.Remove(((DataRowView)this.dgData.SelectedItem).Row);

    4.新增行
    获取DataGrid当前的数据源,创建一个具有相同结构的空行,追加到中间变量_dt,然后重新绑定。这样就保证了原有数据不丢失,同时又增加一个空行。

                _dt = ((DataView)this.dgData.ItemsSource).Table;
                DataRow dr = _dt.NewRow();
                _dt.Rows.Add(dr);
                this.dgData.ItemsSource = _dt.DefaultView;

    其他

    添加样式

    简单的添加了样式,主要是确保行列对齐,看起来不那么丑

        <UserControl.Resources>
            <Style x:Key="ElementStyle" TargetType="FrameworkElement">
                <Setter Property="VerticalAlignment" Value="Center"></Setter>
                <Setter Property="HorizontalAlignment" Value="Center"></Setter>
            </Style>
            <Style x:Key="TextBoxStyle" TargetType="TextBox" BasedOn="{StaticResource ElementStyle}">
                <Setter Property="BorderThickness" Value="1"></Setter>
                <Setter Property="BorderBrush">
                    <Setter.Value>
                        <SolidColorBrush Color="#d6c79b"></SolidColorBrush>
                    </Setter.Value>
                </Setter>
                <Setter Property="MinHeight" Value="24"></Setter>
                <Setter Property="MinWidth" Value="100"></Setter>
                <Setter Property="Margin" Value="5,2,5,2"></Setter>
                <Setter Property="TextAlignment" Value="Center"></Setter>
            </Style>
            <Style x:Key="TextBlockStyle" TargetType="TextBlock" BasedOn="{StaticResource ElementStyle}">
                <Setter Property="MinHeight" Value="24"></Setter>
                <Setter Property="MinWidth" Value="100"></Setter>
                <Setter Property="TextAlignment" Value="Center"></Setter>
            </Style>
            <Style x:Key="ButtonStyle" TargetType="Button">
                <Setter Property="BorderThickness" Value="0"></Setter>
                <Setter Property="Background" Value="Transparent"></Setter>
            </Style>
            <Style TargetType="DataGrid">
                <Setter Property="Background" Value="{x:Null}"></Setter>
                <Setter Property="BorderThickness" Value="0"></Setter>
                <Setter Property="HorizontalGridLinesBrush">
                    <Setter.Value>
                        <SolidColorBrush Color="#d6c79b"></SolidColorBrush>
                    </Setter.Value>
                </Setter>
                <Setter Property="MinRowHeight" Value="32"></Setter>
                <Setter Property="FontSize" Value="14"></Setter>
            </Style>
        </UserControl.Resources>

    添加是否编辑状态的依赖项属性

    为控件又添加了一个用于控制编辑状态的自定义依赖项属性IsEdit。非编辑状态下(IsEdit=false),隐藏新增和删除按钮,表格只读。编辑状态下(IsEdit=true),显示新增和删除按钮,表格可编辑。默认值为可编辑。

        public bool IsEdit
        {
            get { return (bool)GetValue(IsEditProperty); }
            set { SetValue(IsEditProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for IsEdit.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsEditProperty =
            DependencyProperty.Register("IsEdit", typeof(bool), typeof(TableControl), new PropertyMetadata(true, IsEditChanged));
    
        private static void IsEditChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TableControl control = d as TableControl;
            bool isEdit = Convert.ToBoolean(e.NewValue);
            if (!isEdit)
            {
                int len = control.dgData.Columns.Count;
                control.dgData.Columns[len - 1].Visibility = Visibility.Collapsed;
                control.dgData.IsReadOnly = true;
                control.btnAdd.Visibility = Visibility.Collapsed;
            }
        }
    

    完整代码下载点这里

    总体上实现了预期的效果,但还有一些地方需要继续改进,欢迎广大朋友批评指导!

    展开全文
  • swift之自定义表格控件(UITableView)

    千次阅读 2016-03-05 14:10:56
    2、storyboard上的控件就2个:UIButton。 3、通过辅助编辑器为这2个按钮添加按钮单击事件:分别为 generalBtnClick 和 groupBtnClick 4、完整代码: import UIKit enum UIControlType{ case Basic case Advanced ...

    1,效果图


    2、控件

    storyboard上的控件就2个:UIButton。

    3、为按钮添加点击事件

    通过辅助编辑器为这2个按钮添加按钮单击事件:分别为 generalBtnClick 和   groupBtnClick

    4、完整代码:

    import UIKit
    
    enum UIControlType{
        case Basic
        case Advanced
    }
    
    class ViewController: UIViewController , UITableViewDelegate, UITableViewDataSource{
        
        var tableView:UITableView?
        
        var ctrlnames:[String]? = ["按钮", "文本框", "标签"];
        
        var allnames:Dictionary<Int, [String]>?
        
        var adHeaders:[String]?
        
        var ctype:UIControlType!
        
        override func loadView() {
            super.loadView()
        }
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            //        //初始化数据,这一次数据,我们放在属性列表文件里
            //        self.ctrlnames =  NSArray(contentsOfFile: NSBundle.mainBundle().pathForResource("Controls", ofType:"plist")!) as? Array
            //
            //        print(self.ctrlnames, terminator: "")
            
            //初始化数据,这一次数据,我们放在属性列表文件里
            self.allnames =  [ 0:[String](self.ctrlnames!),1:[String]([
                "日期选择器",
                "网页选择器",
                "工具条",
                "表格视图"])
            ];
            
            //        print(self.allnames, terminator: "")
            
            self.adHeaders = [
                "常见UIKit控件",
                "高级UIKit控件"
            ]
        }
        
        @IBAction func generalBtnClicked(sender: UIButton) {
            self.ctype = UIControlType.Basic
            
            
            //创建表视图
            self.tableView = UITableView(frame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 100), style:UITableViewStyle.Plain)
            self.tableView!.delegate = self
            self.tableView!.dataSource = self
            //创建一个重用的单元格
            self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell")
            self.view.addSubview(self.tableView!)
            
            
            //创建表头标签
            let headerLabel = UILabel(frame: CGRectMake(0, 0, self.view.bounds.size.width, 30))
            headerLabel.backgroundColor = UIColor.blackColor()
            headerLabel.textColor = UIColor.whiteColor()
            headerLabel.numberOfLines = 0
            headerLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
            headerLabel.text = "常见 UIKit 控件"
            headerLabel.font = UIFont.italicSystemFontOfSize(20)
            self.tableView!.tableHeaderView = headerLabel
        }
        
        @IBAction func groupBtnClicked(sender: UIButton) {
            self.ctype = UIControlType.Advanced
            
            //创建表视图
            
            
            self.tableView = UITableView(frame:CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.height - 100), style:UITableViewStyle.Grouped)
            self.tableView!.delegate = self
            self.tableView!.dataSource = self
            //创建一个重用的单元格
            self.tableView!.registerClass(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell")
            self.view.addSubview(self.tableView!)
            
            //创建表头标签
            let headerLabel = UILabel(frame: CGRectMake(0, 0, self.view.bounds.size.width, 30))
            headerLabel.backgroundColor = UIColor.blackColor()
            headerLabel.textColor = UIColor.whiteColor()
            headerLabel.numberOfLines = 0
            headerLabel.lineBreakMode = NSLineBreakMode.ByWordWrapping
            headerLabel.text = "高级 UIKit 控件"
            headerLabel.font = UIFont.italicSystemFontOfSize(20)
            self.tableView!.tableHeaderView = headerLabel
        }
        
        
        //在本例中,只有一个分区
        func numberOfSectionsInTableView(tableView: UITableView) -> Int {
            return self.ctype == UIControlType.Basic ? 1:2;
        }
        
        //返回表格行数(也就是返回控件数)
        func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            let data = self.allnames?[section]
            return data!.count
        }
        
        
        // UITableViewDataSource协议中的方法,该方法的返回值决定指定分区的头部
        func tableView(tableView:UITableView, titleForHeaderInSection
            section:Int)->String?
        {
            var headers =  self.adHeaders!;
            return headers[section];
        }
        // UITableViewDataSource协议中的方法,该方法的返回值决定指定分区的尾部
        func tableView(tableView:UITableView, titleForFooterInSection
            section:Int)->String?
        {
            let data = self.allnames?[section]
            return "有\(data!.count)个控件"
        }
        
        
        //创建各单元显示内容(创建参数indexPath指定的单元)
        func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {
            let identify:String = "SwiftCell";
            
            /// 同一形式的单元格重复使用。
            let secno = indexPath.section;
            var data = self.allnames?[secno];
            if (0 == secno)
            {
                let cell = tableView.dequeueReusableCellWithIdentifier(identify, forIndexPath: indexPath);
                cell.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator;
                
                cell.imageView?.image = UIImage(named: "1");
                cell.textLabel?.text = data![indexPath.row];
            
                return cell;
            }
            
            else
            {
                let adcell = UITableViewCell(style: .Subtitle, reuseIdentifier: "SwiftCell");
                adcell.textLabel?.text = data![indexPath.row];
                adcell.detailTextLabel?.text = "这是\(data![indexPath.row])的说明";
                
                return adcell;
            }
        }
        
        // UITableViewDelegate 方法,处理列表项的选中事件
        func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
        {
            self.tableView!.deselectRowAtIndexPath(indexPath, animated: true)
            
            let itemString = self.ctrlnames![indexPath.row]
            
            let  alert = UIAlertController(title: "提示", message: "你选择了:\(itemString)", preferredStyle: UIAlertControllerStyle.Alert);
            let sureAction = UIAlertAction(title: "确定", style: UIAlertActionStyle.Default, handler: {(action)->Void in});
            alert.addAction(sureAction);
            
            presentViewController(alert,animated:true, completion:nil);
            
        }
        
        override func didReceiveMemoryWarning() {
            super.didReceiveMemoryWarning()
            
            // Dispose of any resources that can be recreated.
        }
    }
    


    展开全文
  • TableLayout就是最终呈现的完整表格,实际上他就是多个TableColumn的组合,其主要负责整个表格的大小测量、分割线绘制和接受数据填充。 1.单元格大小测量 @Override protected void onMeasure ( int ...
  • http://www.jianshu.com/p/251cd77fbb60?from=jiantop.com

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 45,637
精华内容 18,254
关键字:

自定义表格控件