using DevExpress.Utils;
using DevExpress.Utils.Helpers;
using DevExpress.Utils.Menu;
using DevExpress.Utils.Paint;
using DevExpress.Utils.Svg;
using DevExpress.XtraBars;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraGrid;
using DevExpress.XtraGrid.Columns;
using DevExpress.XtraGrid.Views.Grid;
using DxHelper;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
public static class GridControlEx
{
    internal class GridTag
    {
        public GridTag() { }
        public PopupMenu PopupMenu { get; set; }

        public BarManager BarM { get; set; }

        public List<BarButtonItem> RowButtonsItems { get; set; } = new List<BarButtonItem>();

        public List<BarButtonItem> MultRowButtonsItems { get; set; } = new List<BarButtonItem>();
    }
    /// <summary>
    /// 初始化表格(默认禁用分组)
    /// </summary>
    /// <param name="grid"></param>
    /// <param name="dataSource">绑定的数据源</param>
    /// <param name="rowHeight">行高(默认24px)</param>
    /// <param name="showScrollH">是否显示水平滚动条(默认不显示)</param>
    /// <typeparam name="T">绑定的数据源模型类型</typeparam>
    /// <returns></returns>
    public static GridControl UseDefault<T>(this GridControl grid, List<T> dataSource, int rowHeight = 24, bool showScrollH = false)
    {
        grid.DataSource = dataSource;
        grid.HideColumn("ID","CreateTime","UpdateTime");
        grid.MainView.BorderStyle = BorderStyles.Flat;
        var view = grid.MainView as GridView;
        view.CustomColumnDisplayText += View_CustomColumnDisplayText;
        view.Appearance.HeaderPanel.TextOptions.HAlignment = HorzAlignment.Center;

        view.Appearance.Row.Options.UseTextOptions = true;
        view.Appearance.Row.TextOptions.HAlignment = HorzAlignment.Center;
        view.OptionsView.ColumnHeaderAutoHeight = DefaultBoolean.True;
        view.RowHeight = rowHeight;
        view.OptionsView.ShowGroupPanel = false;

        view.OptionsBehavior.Editable = false;
        view.OptionsView.ShowDetailButtons = false;
        view.OptionsView.ShowIndicator = false;

        view.OptionsMenu.EnableColumnMenu = true;
        view.OptionsCustomization.AllowFilter = true;
        view.OptionsCustomization.AllowGroup = false;
        view.OptionsCustomization.AllowSort = true;
        view.OptionsCustomization.AllowColumnMoving = true;
        view.OptionsCustomization.AllowMergedGrouping = DefaultBoolean.False;
        view.OptionsSelection.MultiSelect = false;
        view.OptionsCustomization.AllowRowSizing = false;
        view.OptionsCustomization.AllowQuickHideColumns = false;
        view.OptionsMenu.EnableGroupPanelMenu = false;
        view.OptionsMenu.EnableGroupRowMenu = false;
        view.OptionsMenu.EnableFooterMenu = false;
        view.OptionsLayout.StoreAllOptions = true;
        view.OptionsLayout.StoreAppearance = true;
        view.OptionsLayout.StoreDataSettings = true;
        view.OptionsLayout.StoreVisualOptions = true;
        view.OptionsLayout.StoreFormatRules = true;
        view.OptionsView.ColumnAutoWidth = !showScrollH;
        view.PopupMenuShowing += View_PopupMenuShowing;

        view.OptionsSelection.EnableAppearanceFocusedCell = false;
        string GetLayoutName()
        {
            Control ctrl;
            if (view.Tag is SearchLookUpEdit searchLookUpEdit)
                ctrl = searchLookUpEdit;
            else
                ctrl = grid;
            while (ctrl.Parent != null)
            {
                ctrl = ctrl.Parent;
                if (ctrl is UserControl) break;
            }
            var props = typeof(T).GetProperties();
            StringBuilder sb = new StringBuilder();
            foreach (var item in props)
            {
                sb.Append(item.Name);
            }
            var md5 = MD5Helper.StrToMD5(sb.ToString());
            if (view.Tag is SearchLookUpEdit searchLookUpEdit2)
                return $"{ctrl.Name}_{searchLookUpEdit2.Name}_{md5}";
            else
                return $"{ctrl.Name}_{grid.Name}_{md5}";
        }
        string name = GetLayoutName();
        void SaveLayoutAction()
        {

            Form frm = null;
            if (view.Tag is SearchLookUpEdit edit)
                frm = edit.FindForm();
            else
                frm = grid.FindForm();

            if (frm != null)
            {
                frm.VisibleChanged += (sender2, e2) =>
                {
                    Directory.CreateDirectory("Layout");
                    if (name == null) return;
                    grid.MainView?.SaveLayoutToXml($"Layout\\{name}.xml", OptionsLayoutBase.FullLayout);
                };
            }
        }
        if (grid.IsLoaded)
        {
            SaveLayoutAction();
        }
        else
        {
            grid.Load += (sender, e) => SaveLayoutAction();
        }
        if (name != null && File.Exists($"Layout\\{name}.xml"))
        {
            view.RestoreLayoutFromXml($"Layout\\{name}.xml", OptionsLayoutBase.FullLayout);
            view.ClearColumnsFilter();
            view.ClearFindFilter();
            view.ClearInHeaderSearchText();
            view.ClearSorting();
            view.ClearSelection();
        }
        view.KeyUp += View_KeyUp;
        grid.Tag = new GridTag();
        return grid;
    }

    /// <summary>
    /// 为GirdControl启用右键新增数据的功能
    /// </summary>
    /// <param name="grid"></param>
    /// <param name="emptyText"></param>
    /// <returns></returns>
    public static GridControl UseEmptyText(this GridControl grid,  string emptyText = "暂无数据")
    {
        if (string.IsNullOrWhiteSpace(emptyText)) return grid;
        var view = grid.MainView as GridView;
        view.CustomDrawEmptyForeground += (sender, e) =>
        {
            var s = e.Appearance.CalcTextSize(e.Cache, emptyText, e.Bounds.Width).ToSize();
            var x = (e.Bounds.Width - s.Width) / 2;
            var y = (e.Bounds.Height - s.Height) / 2;
            e.Appearance.ForeColor = Color.Gray;
            e.Appearance.DrawString(e.Cache, emptyText, new Rectangle(x, y, s.Width, s.Height));
        };
        return grid;
    }

    /// <summary>
    /// 为GirdControl启用右键新增数据的功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="callback">一个回调函数,返回新增的数据</param>
    /// <returns></returns>
    public static GridControl UseAdd<T>(this GridControl grid, Func<T> callback, string menuCaption = "新增")
    {
        var view = grid.MainView as GridView;
        view.CustomDrawEmptyForeground += (sender, e) =>
        {
            string emptyText = "右键添加";
            var s = e.Appearance.CalcTextSize(e.Cache, emptyText, e.Bounds.Width).ToSize();
            var x = (e.Bounds.Width - s.Width) / 2;
            var y = (e.Bounds.Height - s.Height) / 2;
            e.Appearance.ForeColor = Color.Gray;
            e.Appearance.DrawString(e.Cache, emptyText, new Rectangle(x, y, s.Width, s.Height));
        };
        grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateAdd(), data =>
        {
            if (callback != null)
            {
                var addRow = callback();
                if (addRow == null) return;
                var ds = grid.DataSource as List<T>;
                ds.Add(addRow);
                view.RefreshData();
            }

        }, true);
        return grid;
    }

    /// <summary>
    /// 为GirdControl启用右键新增数据的功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="callback">一个回调函数,返回新增的数据</param>
    /// <returns></returns>
    public static GridControl UseAddAsync<T>(this GridControl grid, Func<Task<T>> callback, string menuCaption = "新增")
    {
        grid.AddContentMenuAsync<T>(menuCaption, DxHelper.SvgHelper.CreateAdd(), async data =>
        {
            if (callback != null)
            {
                var addRow = await callback();
                if (addRow == null) return;
                var view = grid.MainView as GridView;
                var ds = grid.DataSource as List<T>;
                ds.Add(addRow);
                view.RefreshData();
            }

        }, true);
        return grid;
    }

    /// <summary>
    /// 为GridControl启用右编辑选中的单行功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public static GridControl UseEdit<T>(this GridControl grid, Func<T, T> callback, string menuCaption = "编辑")
    {
        grid.AddRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateEdit(), data =>
        {
            if (callback != null)
            {
                var newRow = callback(data);
                if (newRow == null) return;
                var view = grid.MainView as GridView;
                var ds = grid.DataSource as List<T>;
                var idx = ds.IndexOf(data);
                ds.Remove(data);
                ds.Insert(idx, newRow);
                view.RefreshData();
            }

        }, null);
        return grid;
    }

    /// <summary>
    /// 为GridControl启用右编辑选中的单行功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="callback"></param>
    /// <returns></returns>
    public static GridControl UseEditAsync<T>(this GridControl grid, Func<T, Task<T>> callback, string menuCaption = "编辑")
    {
        grid.AddRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateEdit(), async data =>
        {
            if (callback != null)
            {
                var newRow = await callback(data);
                if (newRow == null) return;
                var view = grid.MainView as GridView;
                var ds = grid.DataSource as List<T>;
                var idx = ds.IndexOf(data);
                ds.Remove(data);
                ds.Insert(idx, newRow);
                view.RefreshData();
            }

        }, null);
        return grid;
    }

    /// <summary>
    /// 为GridControl启用右删除选中的一行或多行功能(自动启用UseMultiSelect)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static GridControl UseDelete<T>(this GridControl grid, Func<List<T>, bool> action = null, string menuCaption = "删除")
    {
        grid.AddMultRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClose(), data =>
        {
            if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认删除选中的记录?共[{data.Count}]条")) return;
            if (action != null)
            {
                bool succeed = action(data);
                if (!succeed) return;
            }
            var view = grid.MainView as GridView;
            view.DeleteSelectedRows();
            view.RefreshData();

        });
        return grid;
    }

    /// <summary>
    /// 为GridControl启用右删除选中的一行或多行功能(自动启用UseMultiSelect)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static GridControl UseDeleteAsync<T>(this GridControl grid, Func<List<T>, Task<bool>> action = null, string menuCaption = "删除")
    {
        grid.AddMultRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClose(), async data =>
        {
            if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认删除选中的记录?共[{data.Count()}]条")) return;
            if (action != null)
            {
                bool succeed = await action(data);
                if (!succeed) return;
            }
            var view = grid.MainView as GridView;
            view.DeleteSelectedRows();
            view.RefreshData();

        });
        return grid;
    }

    /// <summary>
    /// 为GirdControl启用右键清除所有数据的功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static GridControl UseClear<T>(this GridControl grid, Func<List<T>, bool> action = null, string menuCaption = "清除")
    {
        grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClear(), data =>
        {
            if (data == null || data.Count == 0) return;
            if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认清空所有记录?共[{data.Count}]条")) return;
            if (action != null)
            {
                bool succeed = action(data);
                if (!succeed) return;
            }
            var view = grid.MainView as GridView;
            data.Clear();
            view.RefreshData();

        }, false);
        return grid;
    }
    public static GridControl SetLogImageColumn(this GridControl grid, string columnFieldName,Type enumType)
    {
        var view = grid.MainView as GridView;
        RepositoryItemImageComboBox edit = new RepositoryItemImageComboBox();
        edit.AddEnum(enumType);
        SvgImageCollection svgImages = new SvgImageCollection();
        svgImages.ImageSize = new System.Drawing.Size(20, 20);
        svgImages.Add(SvgHelper.CreateInfo());
        svgImages.Add(SvgHelper.CreateWarning());
        svgImages.Add(SvgHelper.CreateError());
        edit.SmallImages = svgImages;
        edit.GlyphAlignment = DevExpress.Utils.HorzAlignment.Center;
        view.Columns[columnFieldName].ColumnEdit = edit;
        return grid;
    }

    /// <summary>
    /// 为GirdControl启用右键清除所有数据的功能
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="grid"></param>
    /// <param name="menuCaption"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    public static GridControl UseClearAsync<T>(this GridControl grid, Func<List<T>, Task<bool>> action = null, string menuCaption = "清除")
    {
        grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClear(), async data =>
        {
            if (data == null || data.Count == 0) return;
            if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认清空所有记录?共[{data.Count}]条")) return;
            if (action != null)
            {
                bool succeed = await action(data);
                if (!succeed) return;
            }
            var view = grid.MainView as GridView;
            data.Clear();
            view.RefreshData();

        }, false);
        return grid;
    }

    public static GridControl UseExportCsv(this GridControl grid)
    {
        GridTag tag = grid.Tag as GridTag;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }

        PopupMenu popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        item.ItemClick += (sender, e) =>
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "csv|*.csv";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                var view = grid.MainView as GridView;
                view.ExportToCsv(dialog.FileName);
            }
        };
        item.ImageOptions.SvgImage = DxHelper.SvgHelper.CreateExportCsv();
        item.Caption = "导出(CSV)";
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }

    public static GridControl UseExportXlsx(this GridControl grid)
    {
        GridTag tag = grid.Tag as GridTag;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }

        PopupMenu popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        item.ItemClick += (sender, e) =>
        {
            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "Excel文件|*.xlsx";
            if (dialog.ShowDialog() == DialogResult.OK)
            {
                var view = grid.MainView as GridView;
                view.ExportToXlsx(dialog.FileName);
            }
        };
        item.ImageOptions.SvgImage = DxHelper.SvgHelper.CreateExportXlsx();
        item.Caption = "导出(Excel)";
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }
    private static void View_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.Control && e.Shift & e.KeyCode == Keys.C)
        {
            var view = sender as GridView;
            if (view.FocusedColumn == null) return;
            var val = view.GetFocusedRowCellDisplayText(view.FocusedColumn);
            if (string.IsNullOrWhiteSpace(val)) return;
            Clipboard.SetText(val);
        }
    }

    private static void View_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
    {
        if (e.Column.ColumnType == typeof(DateTime) || e.Column.ColumnType == typeof(DateTime?))
        {
            if (e.Value == null) return;
            if (e.Column.FieldName == "SigTime")
                e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm:ss.fff");
            else
                e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm:ss");

        }
    }
    public static GridControl ShowColumn(this GridControl grid, params string[] colField)
    {
        var view = grid.MainView as GridView;
        if (view.Columns.Count == 0) return grid;
        if (colField == null || colField.Length == 0) return grid;
        foreach (GridColumn item in view.Columns)
        {
            if (colField.Contains(item.FieldName))
                item.Visible = true;
        }
        return grid;
    }
    public static GridControl UseMultiSelect(this GridControl grid)
    {
        var view = grid.MainView as GridView;
        view.OptionsSelection.MultiSelect = true;
        view.OptionsSelection.MultiSelectMode = GridMultiSelectMode.RowSelect;
        return grid;
    }
    public static GridControl UseGroup(this GridControl grid)
    {
        var view = grid.MainView as GridView;
        view.OptionsView.GroupFooterShowMode = GroupFooterShowMode.Hidden;
        view.OptionsView.ShowGroupPanel = true;
        view.OptionsCustomization.AllowGroup = true;
        view.OptionsCustomization.AllowSort = true;

        return grid;
    }
    public static GridControl UseFooter(this GridControl grid, Action<object, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs> act)
    {
        var view = grid.MainView as GridView;
        view.OptionsView.ShowFooter = true;
        view.CustomDrawFooter += (s, e) => act(s, e);
        return grid;

    }
    public static GridControl UseEdit(this GridControl grid)
    {
        var view = grid.MainView as GridView;
        view.OptionsBehavior.Editable = true;
        view.OptionsSelection.EnableAppearanceFocusedCell = true;
        foreach (GridColumn item in view.Columns)
        {
            item.OptionsColumn.AllowEdit = false;
        }
        return grid;
    }
    public static GridControl UseRowNumber(this GridControl grid)
    {
        var view = grid.MainView as GridView;
        view.OptionsView.ShowIndicator = true;
        view.CustomDrawRowIndicator += (s, e) =>
        {
            if (!e.Info.IsRowIndicator) return;
            if (e.RowHandle < 0) return;
            e.Handled = true;
            string txt = (e.RowHandle + 1).ToString();
            var txtSize = e.Graphics.MeasureString(txt, e.Appearance.Font);
            if (view.IndicatorWidth < txtSize.Width + 20)
            {
                view.IndicatorWidth++;
            }
            var loc = new PointF(e.Bounds.X + e.Bounds.Width / 2f - txtSize.Width / 2f + 2,
                e.Bounds.Y + e.Bounds.Height / 2f - txtSize.Height / 2f);

            e.Cache.FillRectangle(new SolidBrush(e.Appearance.BackColor), e.Bounds);
            e.Cache.DrawString(txt, e.Appearance.Font, new SolidBrush(e.Appearance.ForeColor), loc);
        };
        view.RowCountChanged += (sender, e) =>
        {
            if (view.RowCount == 0)
                view.IndicatorWidth = -1;
            else
                view.IndicatorWidth = view.RowCount.ToString().Length * 6 + 20;
        };
        return grid;

    }

    public static GridControl UseNullValueText(this GridControl grid, string nullText = "--")
    {
        var view = grid.MainView as GridView;
        view.CustomColumnDisplayText += (sender, e) =>
        {
            if (e.Value == null) e.DisplayText = nullText;
        };
        return grid;
    }

    public static GridControl SetDisplayText(this GridControl grid, string columnFieldName, Func<object, string> action)
    {
        var view = grid.MainView as GridView;
        view.CustomColumnDisplayText += (sender, e) =>
        {
            if (e.Column.FieldName != columnFieldName) return;
            if (e.Value == null || action == null) return;
            e.DisplayText = action(e.Value);
        };
        return grid;
    }
    public static GridControl HideColumn(this GridControl grid, params string[] colField)
    {

        var view = grid.MainView as GridView;
        if (colField == null || colField.Length == 0) return grid;
        foreach (GridColumn item in view.Columns)
        {
            if (colField.Contains(item.FieldName))
                item.Visible = false;
        }
        return grid;
    }


    /// <summary>
    /// GridControl添加单行元素选择后的右键菜单
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的事件函数,参数为选中的单行元素</param>
    /// <param name="showCondition">菜单显示的条件</param>
    /// <returns></returns>
    public static GridControl AddRowMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
        Action<T> action, Func<T, bool> showCondition = null)
    {
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;

        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        tag.RowButtonsItems.Add(item);
        Func<bool> showConditionAll = () =>
        {
            if (!view.GetSelectedRows().Any()) return false;
            if (showCondition == null)
                return true;
            else
                return showCondition((T)view.GetFocusedRow());
        };
        item.Tag = showConditionAll;
        var handle = new ItemClickEventHandler((sender, e) =>
        {
            if (action != null)
            {
                if (view.GetFocusedRow() == null) return;
                item.Enabled = false;
                action.Invoke((T)view.GetFocusedRow());
                item.Enabled = true;
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }

    /// <summary>
    /// GridControl添加单行元素选择后的右键菜单
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的异步事件函数,参数为选中的单行元素</param>
    /// <param name="showCondition">菜单显示的条件</param>
    /// <returns></returns>
    public static GridControl AddRowMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
   Func<T, Task> action, Func<T, bool> showCondition = null)
    {
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;

        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        tag.RowButtonsItems.Add(item);
        Func<bool> showConditionAll = () =>
        {
            if (!view.GetSelectedRows().Any()) return false;
            if (showCondition == null)
                return true;
            else
                return showCondition((T)view.GetFocusedRow());
        };
        item.Tag = showConditionAll;
        var handle = new ItemClickEventHandler(async (sender, e) =>
        {
            if (action != null)
            {
                if (view.GetFocusedRow() == null) return;
                item.Enabled = false;
                await action.Invoke((T)view.GetFocusedRow());
                item.Enabled = true;
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }




    /// <summary>
    /// GridControl添加多行选择元素的右键菜单(自动启用UseMultiSelect)
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的事件,参数为选中的一行或多行元素</param>
    /// <returns></returns>
    public static GridControl AddMultRowMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
        Action<List<T>> action)
    {
        grid.UseMultiSelect();
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        var handle = new ItemClickEventHandler((sender, e) =>
        {
            if (action != null)
            {
                var rows = view.GetSelectedRows();
                List<T> list = new List<T>();
                foreach (var row in rows)
                {
                    if (row < 0) continue;
                    list.Add((T)view.GetRow(row));
                }
                if (list.Any())
                    action.Invoke(list);
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        Func<bool> showCondition = () => view.GetSelectedRows().Any();
        item.Tag = showCondition;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }

    /// <summary>
    /// GridControl添加多行选择元素的右键菜单(自动启用UseMultiSelect)
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的异步事件函数,参数为选中的一行或多行元素</param>
    /// <returns></returns>
    public static GridControl AddMultRowMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
        Func<List<T>, Task> action)
    {
        grid.UseMultiSelect();
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        var handle = new ItemClickEventHandler(async (sender, e) =>
        {
            if (action != null)
            {
                var rows = view.GetSelectedRows();
                List<T> list = new List<T>();
                foreach (var row in rows)
                {
                    if (row < 0) continue;
                    list.Add((T)view.GetRow(row));
                }
                if (list.Any())
                    await action.Invoke(list);
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        Func<bool> showCondition = () => view.GetSelectedRows().Any();
        item.Tag = showCondition;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }

    /// <summary>
    /// GridControl添加内容区的右键菜单
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的事件,参数为绑定的数据源</param>
    /// <param name="showWithNoneDataRow">内容区没有元素时是否显示此菜单,默认显示</param>
    /// <returns></returns>
    public static GridControl AddContentMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
        Action<List<T>> action, bool showWithNoneDataRow = true)
    {
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        var handle = new ItemClickEventHandler((sender, e) =>
        {
            if (action != null)
            {
                var ds = grid.DataSource as List<T>;
                if (!showWithNoneDataRow && (ds == null || ds.Count == 0)) return;
                item.Enabled = false;
                action.Invoke(ds);
                item.Enabled = true;
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }
    /// <summary>
    /// GridControl添加内容区的右键菜单
    /// </summary>
    /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
    /// <param name="grid">GridControl控件</param>
    /// <param name="menuText">菜单标题</param>
    /// <param name="meunImage">菜单图标</param>
    /// <param name="action">菜单要执行的事件,参数为绑定的数据源</param>
    /// <param name="showWithNoneDataRow">内容区没有元素时是否显示此菜单,默认显示</param>
    /// <returns></returns>
    public static GridControl AddContentMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
        Func<List<T>, Task> action, bool showWithNoneDataRow = true)
    {
        GridTag tag = grid.Tag as GridTag;
        var view = grid.MainView as GridView;
        if (tag.BarM == null)
        {
            tag.BarM = new BarManager();
            tag.BarM.Form = grid;
        }
        if (tag.PopupMenu == null)
        {
            tag.PopupMenu = new PopupMenu();
        }
        var popupMenu = tag.PopupMenu;
        BarButtonItem item = new BarButtonItem();
        var handle = new ItemClickEventHandler(async (sender, e) =>
        {
            if (action != null)
            {
                var ds = grid.DataSource as List<T>;
                if (!showWithNoneDataRow && (ds == null || ds.Count == 0)) return;
                item.Enabled = false;
                await action.Invoke(ds);
                item.Enabled = true;
            }
        });
        item.Events().AddHandler(menuText, handle);
        item.ItemClick += handle;
        item.ImageOptions.SvgImage = meunImage;
        item.Caption = menuText;
        tag.BarM.Items.Add(item);
        popupMenu.AddItem(item);
        popupMenu.Manager = tag.BarM;
        tag.PopupMenu = popupMenu;
        return grid;
    }
    private static void View_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
    {
        if (e.Menu != null)
        {
            foreach (DXMenuItem item in e.Menu.Items)
            {
                if (!item.Enabled)
                {
                    item.Visible = false;
                    continue;
                }
            }
        }
        //if (e.HitInfo.HitTest == DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitTest.EmptyRow)
        //{
        //    return;
        //}
        var view = sender as GridView;
        var grid = view.GridControl;
        var p = grid.PointToScreen(e.Point);
        var tag = grid.Tag as GridTag;
        if (tag?.PopupMenu != null)
        {
            foreach (BarButtonItemLink item in tag?.PopupMenu?.ItemLinks)
            {
                var buttonItem = item.Item;
                if (buttonItem.Tag != null && buttonItem.Tag is Func<bool> showCondition)
                {

                    if (showCondition())
                        buttonItem.Visibility = BarItemVisibility.Always;
                    else
                        buttonItem.Visibility = BarItemVisibility.Never;
                }
            }
            tag?.PopupMenu?.ShowPopup(p);
        }

    }
    public static GridControl DrawGridColumnHeaderCheckBox(this GridControl grid)
    {
        //View的 Editable要为true
        var view = grid.MainView as GridView;
        view.OptionsBehavior.Editable = true;
        view.OptionsSelection.MultiSelect = true;
        view.OptionsSelection.MultiSelectMode = GridMultiSelectMode.CheckBoxRowSelect;
        foreach (GridColumn item in view.Columns)
        {
            item.OptionsColumn.AllowEdit = false;
        }
        return grid;
    }
}

