using AR; using FarPoint.CalcEngine; using FarPoint.Excel; using FarPoint.Excel.EntityClassLibrary.DrawingEx; using NetOffice.OfficeApi.Enums; using NetOffice.OutlookApi; using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Entity.Core.Mapping; using System.Drawing; using System.Linq; using System.Runtime.CompilerServices; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace FPJ0000.JobReport_ { public partial class fJobProcessSelect : Form { string FullName = string.Empty; string GroupCode = "15"; bool IsAdmin = false; public fJobProcessSelect(string fullname, bool isAdmin = false) { InitializeComponent(); this.IsAdmin = isAdmin; this.FullName = fullname; this.dsJobReport.Common.TableNewRow += Common_TableNewRow; this.FormClosing += FJobProcessManager_FormClosing; this.KeyPreview = true; this.KeyDown += (s1, e1) => { if (e1.KeyCode == Keys.Escape) this.Close(); }; // 이벤트 핸들러 연결 treeView1.ItemDrag += TreeView1_ItemDrag; treeView1.DragEnter += TreeView1_DragEnter; treeView1.DragDrop += TreeView1_DragDrop; //var auth = (FCOMMON.info.Login.level >= 5 || isAdmin); btSave.Visible = isAdmin; btDelete.Visible = isAdmin; btImport.Visible = isAdmin; panel1.Visible = isAdmin; btRefreshTreeview.Visible = isAdmin; lbWarningManager.Visible = isAdmin; lbWarningUser.Visible = !isAdmin; btSelect.Visible = !isAdmin; if (fullname.isEmpty() == false) { this.Text = $"작업형태 선택(기존값:{fullname})"; var buf = fullname.Split('|'); var prc = buf[0].Trim(); this.tbProcessE.Text = prc; this.tbProcessI.Text = prc; this.tbProcessI.Enabled = false; this.tbProcessE.Enabled = false; } } private void TreeView1_ItemDrag(object sender, ItemDragEventArgs e) { // Ctrl 키가 눌린 상태면 복사, 아니면 이동 if (IsAdmin == false) return; DragDropEffects effect = (ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move; DoDragDrop(e.Item, effect); } private void TreeView1_DragEnter(object sender, DragEventArgs e) { if (IsAdmin == false) return; // 드래그한 항목이 TreeNode인 경우에만 허용 if (e.Data.GetDataPresent(typeof(TreeNode))) { // Ctrl 키가 눌린 상태면 복사 효과 표시 e.Effect = (ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move; } else { e.Effect = DragDropEffects.None; } } private void TreeView1_DragDrop(object sender, DragEventArgs e) { if (this.bn.Enabled == false) { AR.UTIL.MsgE("권한이 없어 drag & drop 을 사용할 수 없습니다"); return; } if (IsAdmin == false) return; // 드롭된 위치의 노드 찾기 Point pt = treeView1.PointToClient(new Point(e.X, e.Y)); TreeNode destinationNode = treeView1.GetNodeAt(pt); TreeNode draggedNode = (TreeNode)e.Data.GetData(typeof(TreeNode)); // 자기 자신이나 자식 노드로는 이동할 수 없음 if (destinationNode == null || draggedNode == destinationNode || IsChildNode(draggedNode, destinationNode)) { return; } var dr = draggedNode.Tag as dsJobReport.CommonRow; if (e.Effect == DragDropEffects.Move) //이동한다면 기존 데이터는 삭제한다 { draggedNode.Remove(); } var inseritem = e.Effect == DragDropEffects.Copy; if (draggedNode.Level == 1) //분류를 움직이고 있다 { if (destinationNode.Level == 2) { var idx = destinationNode.Parent.Parent.Nodes.Add((TreeNode)draggedNode.Clone()); var cnd = destinationNode.Parent.Parent.Nodes[idx]; UpdateParentInfo(cnd, inseritem); } else if (destinationNode.Level == 1) { var idx = destinationNode.Parent.Nodes.Add((TreeNode)draggedNode.Clone()); var cnd = destinationNode.Parent.Nodes[idx]; UpdateParentInfo(cnd, inseritem); } else { var idx = destinationNode.Nodes.Add((TreeNode)draggedNode.Clone()); var cnd = destinationNode.Nodes[idx]; UpdateParentInfo(cnd, inseritem); } //AR.UTIL.MsgE("카테고리 이동은 불가 합니다"); } else { // 노드 이동 if (destinationNode.Level > 2) { UTIL.MsgE("최하위 레벨이하로는 이동할 수 없습니다"); } else if (destinationNode.Level > 1) { var idx = destinationNode.Parent.Nodes.Add((TreeNode)draggedNode.Clone()); var cnd = destinationNode.Parent.Nodes[idx]; UpdateParentInfo(cnd, inseritem); } else { var idx = destinationNode.Nodes.Add((TreeNode)draggedNode.Clone()); var cnd = destinationNode.Nodes[idx]; UpdateParentInfo(cnd, inseritem); } } } void UpdateParentInfo(TreeNode cnd, bool newitem) { if (cnd.Level == 2) //최하위 { var grp = cnd.Parent.Text; var prc = cnd.Parent.Parent.Text; //신규로추가를 해준다 if (newitem) { dsJobReport.CommonRow ndr = this.dsJobReport.Common.NewCommonRow(); ndr.svalue2 = prc; ndr.svalue = grp; ndr.memo = cnd.Text; ndr.wuid = FCOMMON.info.Login.no; ndr.wdate = DateTime.Now; ndr.grp = this.GroupCode; ndr.code = makenewcode(); this.dsJobReport.Common.AddCommonRow(ndr); cnd.Tag = ndr; } else { //기존정보를 업데이트한다 var dr = cnd.Tag as dsJobReport.CommonRow; dr.svalue = grp; dr.svalue2 = prc; dr.EndEdit(); } } else if (cnd.Level == 1) //분류(하위항목업데이트필요) { var prc = cnd.Parent.Text; foreach (TreeNode nd in cnd.Nodes) { //신규로추가를 해준다 if (newitem) { dsJobReport.CommonRow ndr = this.dsJobReport.Common.NewCommonRow(); ndr.svalue2 = prc; ndr.svalue = cnd.Text; ndr.memo = nd.Text; ndr.wuid = FCOMMON.info.Login.no; ndr.wdate = DateTime.Now; ndr.grp = this.GroupCode; ndr.code = makenewcode(); this.dsJobReport.Common.AddCommonRow(ndr); nd.Tag = cnd; } else { var dr = nd.Tag as dsJobReport.CommonRow; dr.svalue2 = prc; dr.EndEdit(); } } } else if (cnd.Level == 0) //프로세스(하위항모업데이트필요) { } this.treeView1.SelectedNode = cnd; this.treeView1.SelectedNode.EnsureVisible(); this.treeView1.Focus(); } private bool IsChildNode(TreeNode parent, TreeNode node) { // 대상 노드가 현재 노드의 자식인지 확인 if (node.Parent == null) return false; if (node.Parent == parent) return true; return IsChildNode(parent, node.Parent); } private void FJobProcessManager_FormClosing(object sender, FormClosingEventArgs e) { if (haschanged() == true) { var dlg = UTIL.MsgQ("변경된 내용이 있습니다 그래도 화면을 닫을까요?"); if (dlg != DialogResult.Yes) { e.Cancel = true; return; } } } bool haschanged() { var dt = this.dsJobReport.Common.GetChanges(); if (dt == null) return false; if (dt.Rows.Count < 1) return false; return true; } private void Common_TableNewRow(object sender, DataTableNewRowEventArgs e) { e.Row["wdate"] = DateTime.Now; e.Row["wuid"] = FCOMMON.info.Login.no; e.Row["gcode"] = FCOMMON.info.Login.gcode; e.Row["grp"] = this.GroupCode; } private void commonBindingNavigatorSaveItem_Click(object sender, EventArgs e) { this.Validate(); this.bs.EndEdit(); if (this.haschanged() == false) { UTIL.MsgI("변경된 내용이 없습니다"); return; } try { var cnt = this.tam.UpdateAll(this.dsJobReport); AR.UTIL.MsgI($"{cnt}건의 자료가 업데이트 되었습니다"); RefreshTreeview(); } catch (System.Exception ex) { UTIL.MsgE(ex.Message); } } private void RefreshData() { try { var fullname = this.FullName.Split('|'); var pc = fullname[0].ToString(); var grp = fullname.Length > 2 ? fullname[1].Trim() : string.Empty; if (pc.isEmpty()) { this.ta.Fill(this.dsJobReport.Common, FCOMMON.info.Login.gcode, GroupCode); } else { this.ta.FillByJobProcess(this.dsJobReport.Common, FCOMMON.info.Login.gcode, GroupCode, pc); if(this.dsJobReport.Common.Any()==false) { AR.UTIL.MsgE($"입력된 Process:{pc}에 해당하는 분류가 없어 전체목록을 조회 합니다"); this.ta.Fill(this.dsJobReport.Common, FCOMMON.info.Login.gcode, GroupCode); } } this.commonDataGridView.AutoResizeColumns(); } catch (System.Exception ex) { AR.UTIL.MsgE(ex.Message); } RefreshTreeview(); } private void fJobProcessManager_Load(object sender, EventArgs e) { RefreshData(); this.Show(); System.Windows.Forms.Application.DoEvents(); this.treeView1.Focus(); int curLevel = Math.Max(FCOMMON.info.Login.level, FCOMMON.DBM.getAuth(FCOMMON.DBM.eAuthType.jobreport)); this.bn.Enabled = (curLevel >= 5); this.button2.Enabled = bn.Enabled; this.btAdd.Enabled = bn.Enabled; this.btEdit.Enabled = bn.Enabled; this.groupBox3.Enabled = bn.Enabled; this.groupBox4.Enabled = bn.Enabled; this.commonDataGridView.ReadOnly = !bn.Enabled; } void RefreshTreeview() { this.treeView1.Nodes.Clear(); //dsJobReport.AcceptChanges(); var items = this.dsJobReport.Common.Where(t => t.RowState != DataRowState.Detached && t.RowState != DataRowState.Deleted && string.IsNullOrEmpty(t.svalue)); foreach (var item in items) { item.svalue = "N/A"; item.EndEdit(); } //선택된 항목이 있따면 해당 항목을 선택해준다. var selectedpath = this.FullName.Split('|'); var bAutoselect = selectedpath.Length == 3; var SelPRC = bAutoselect ? selectedpath[0].Trim() : string.Empty; var SelGRP = bAutoselect ? selectedpath[1].Trim() : string.Empty; var SelITM = bAutoselect ? selectedpath[2].Trim() : string.Empty; if (SelPRC.isEmpty()) SelPRC = "N/A"; var grp_process = dsJobReport.Common.OrderBy(t => t.svalue2).GroupBy(t => t.svalue2); TreeNode autoSelectNode = null; foreach (var prc in grp_process) { var prcname = prc.Key; if (prcname.isEmpty()) prcname = "N/A"; if (prcname.Equals("(N/A)")) prcname = "N/A"; var nd = treeView1.Nodes.Add(prcname, prcname); //add process node var grp_jobtype = prc.OrderBy(t => t.svalue).GroupBy(t => t.svalue); foreach (var grp in grp_jobtype) //job type { var nd2 = nd.Nodes.Add(grp.Key, grp.Key); var grpname = grp.Key; foreach (var item in grp.OrderBy(t => t.memo)) { var nd3 = nd2.Nodes.Add(item.memo, item.memo); //job item if (prcname.Equals("N/A")) nd3.ForeColor = Color.DimGray; else nd3.ForeColor = Color.Black; nd3.Tag = item; if (bAutoselect) { if (prcname.Equals(SelPRC) && grpname.Equals(SelGRP) && item.memo.Equals(SelITM)) { autoSelectNode = nd3; } } } } } this.treeView1.CollapseAll(); groupBox3.Enabled = false; if (autoSelectNode != null) { this.treeView1.SelectedNode = autoSelectNode; this.treeView1.SelectedNode.EnsureVisible(); this.treeView1.SelectedNode.Expand(); this.treeView1.Focus(); } else { if(this.treeView1.Nodes.Count > 0) this.treeView1.Nodes[0].Expand(); } } private void tbFind_KeyDown(object sender, KeyEventArgs e) { var search = tbFind.Text.Trim(); if (e.KeyCode == Keys.Enter) { try { var cols = new string[] { "svalue", "memo" }; var filterstring = ""; foreach (var col in cols) { if (filterstring.Length > 0) filterstring += $" or "; filterstring += $"{col} like '%{search}%'"; } if (search.isEmpty()) { this.bs.Filter = ""; tbFind.BackColor = Color.White; } else { this.bs.Filter = filterstring; tbFind.BackColor = Color.Lime; } } catch (System.Exception ex) { AR.UTIL.MsgE(ex.Message); tbFind.BackColor = Color.HotPink; } tbFind.Focus(); tbFind.SelectAll(); } } private void groupBox2_Enter(object sender, EventArgs e) { } private void button1_Click(object sender, EventArgs e) { RefreshTreeview(); } private void btEdit_Click(object sender, EventArgs e) { //edit var prc = tbProcessE.Text.Trim(); var grp = tbTypeE.Text.Trim(); var item = tbItemE.Text.Trim(); if (item.isEmpty()) { UTIL.MsgE("형태는 반드시 입력되어야 합니다"); tbItemE.Focus(); return; } if (prc.isEmpty()) { UTIL.MsgE("프로세스가 입력되지 않았습니다"); tbProcessE.Focus(); return; } var nd = this.treeView1.SelectedNode; if (nd == null) { UTIL.MsgE("선택된 노드가 없습니다"); return; } if (nd.Tag == null) { UTIL.MsgE("선택노드에 정보가 없습니다\n개발자 문의"); return; } //동일데이터가있는지확인 var exist = this.dsJobReport.Common.Where(t => t.RowState != DataRowState.Deleted && t.svalue2.Equals(prc) && t.svalue.Equals(grp) && t.memo.Equals(item)).Any(); if (exist) { UTIL.MsgE("동일한 항목이 존재합니다 / 확인 후 다시 진행 하세요"); return; } var dr = nd.Tag as dsJobReport.CommonRow; if (dr == null) return; var changecate = (dr.svalue2.Equals(prc) == false || dr.svalue.Equals(grp) == false); dr.svalue2 = prc; dr.svalue = grp; dr.memo = item; dr.EndEdit(); //카테고리가 변경되었다면 위치를 이동시켜야한다 nd.Remove(); //선택노드를 삭제한다. AddNode(prc,grp, item, dr); } void AddNode(string prc, string grp, string item, dsJobReport.CommonRow dr) { //프로세스 노드 선택 TreeNode tn_grp = null; TreeNode tn_prc = null; if (grp.isEmpty()) grp = "N/A"; if (prc.isEmpty()) prc = "N/A"; var prc_nodes = this.treeView1.Nodes.Find(prc, false); if (prc_nodes.Any() == false) { tn_prc = treeView1.Nodes.Add(prc, prc); //신규노드추가 } else { tn_prc = prc_nodes.First(); //첫번째 노드로 변경 } var grp_nodes = tn_prc.Nodes.Find(grp, false); if (grp_nodes.Any() == false) { tn_grp = tn_prc.Nodes.Add(grp, grp); //신규노드추가 } else { tn_grp = grp_nodes.First(); //첫번째 노드로 변경 } //아이템노드확인 TreeNode tn_item = null; var item_nodes = tn_grp.Nodes.Find(item, false); if (item_nodes.Any() == false) { tn_item = tn_grp.Nodes.Add(item, item); //신규노드추가 } else { tn_item = item_nodes.First(); //동일한 노드이다 } tn_item.Tag = dr; treeView1.SelectedNode = tn_item; treeView1.SelectedNode.EnsureVisible(); } private void button3_Click(object sender, EventArgs e) { //add var grp = tbTypeA.Text.Trim(); var item = tbItemA.Text.Trim(); var prc = tbProcessI.Text.Trim(); if (prc.isEmpty()) { UTIL.MsgE("프로세스가 입력되지 않았습니다"); tbProcessI.Focus(); return; } if (item.isEmpty()) { UTIL.MsgE("형태는 반드시 입력되어야 합니다"); tbItemA.Focus(); return; } //동일데이터가있는지확인 var exist = this.dsJobReport.Common.Where(t => t.RowState != DataRowState.Deleted && t.svalue2.Equals(prc) && t.svalue.Equals(grp) && t.memo.Equals(item)).Any(); if (exist) { UTIL.MsgE("동일한 항목이 존재합니다 / 확인 후 다시 진행 하세요"); tbItemA.Focus(); tbItemA.SelectAll(); return; } var dr = this.dsJobReport.Common.NewCommonRow(); dr.svalue2 = prc; dr.svalue = grp; dr.memo = item; dr.wuid = FCOMMON.info.Login.no; dr.wdate = DateTime.Now; dr.grp = this.GroupCode; dr.code = makenewcode(); this.dsJobReport.Common.AddCommonRow(dr); AddNode(prc, grp, item, dr); tbItemA.Focus(); tbItemA.SelectAll(); } string makenewcode() { string lastcodename = ""; var lastcodedr = dsJobReport.Common.OrderByDescending(t => t.code).FirstOrDefault(); if (lastcodedr != null) lastcodename = lastcodedr.code; int newnum = 0; int codenameleng = lastcodename.Length; if (codenameleng == 0) codenameleng = 4; if (int.TryParse(lastcodename, out int lastcodenum) == false) { //숫자로되어있지 않다 newnum = 1;// newnum.PadLeft(codenameleng, '0'); } else { //숫자로되어있으니 +1해서 처리한다. newnum = (lastcodenum + 1); } var newnumstr = newnum.ToString().PadLeft(codenameleng, '0'); return newnumstr; } private void tv_AfterSelect(object sender, TreeViewEventArgs e) { label8.Text = "Path://"; var tn = this.treeView1.SelectedNode; if (tn == null) return; if (tn.Tag == null) return; this.label8.Text = tn.FullPath; var dr = tn.Tag as dsJobReport.CommonRow; if (dr == null) return; tbTypeE.Text = dr.svalue; tbTypeA.Text = dr.svalue; tbItemE.Text = dr.memo; tbItemA.Text = dr.memo; tbProcessE.Text = dr.svalue2; tbProcessI.Text = dr.svalue2; groupBox3.Enabled = true; groupBox3.Text = $"선택자료 편집({dr.idx})"; } private void tbItemA_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) btAdd.PerformClick(); } private void tbItemE_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) btEdit.PerformClick(); } private void button2_Click_1(object sender, EventArgs e) { //선택노드삭제 var nd = this.treeView1.SelectedNode; if (nd == null) { UTIL.MsgE("선택된 노드가 없습니다"); return; } if (nd.Tag == null) { UTIL.MsgE("선택노드에 정보가 없습니다\n최하위 아이템을 선택하세요\n오류가 반복되면 개발사에 문의 하세요"); return; } //동일데이터가있는지확인 var dr = nd.Tag as dsJobReport.CommonRow; var grp = dr.svalue; var prc = dr.svalue2; var item = dr.memo; var exist = this.dsJobReport.Common.Where(t => t.RowState != DataRowState.Deleted && t.svalue2.Equals(prc) && t.svalue.Equals(grp) && t.memo.Equals(item)).FirstOrDefault(); if (exist == null) { UTIL.MsgE("해당 데이터를 찾지 못했습니다\n잠시 후 다시 시도하세요"); return; } exist.Delete(); // dsJobReport.Common.RemoveCommonRow(exist); nd.Remove(); //RefreshTreeview(); } private void btDelete_Click(object sender, EventArgs e) { RefreshTreeview(); } private void btInsert_Click(object sender, EventArgs e) { } private void treeView1_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Delete) { var nd = this.treeView1.SelectedNode; if (nd == null) return; if (nd.Level == 2) { var dr = nd.Tag as dsJobReport.CommonRow; nd.Remove(); dr.Delete(); } else { UTIL.MsgE("최하위 항목만 삭제 가능합니다"); } } } private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e) { if (this.FullName.isEmpty()) return; //노드에서 항목 더블클릭 var nd = this.treeView1.SelectedNode; if (nd == null) return; if (nd.Level < 1) return; var dr = nd.Tag as dsJobReport.CommonRow; if (dr == null) return; Feedback(dr); } private void btSelect_Click(object sender, EventArgs e) { //트리뷰항목 선택 var nd = this.treeView1.SelectedNode; if (nd == null) return; if (nd.Level < 1) { UTIL.MsgE("최하위 항목을 선택하세요"); return; } var dr = nd.Tag as dsJobReport.CommonRow; if (dr == null) return; Feedback(dr); } private void commonDataGridView_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e) { } void Feedback(dsJobReport.CommonRow dr) { var prc = dr.svalue2; var grp = dr.svalue; var itm = dr.memo; if (grp.isEmpty()) grp = "N/A"; this.SelectedValue = $"{prc}|{grp}|{itm}"; DialogResult = DialogResult.OK; } public string SelectedValue { get; set; } = ""; private void 클립보드에서ToolStripMenuItem_Click(object sender, EventArgs e) { if(this.haschanged()) { AR.UTIL.MsgE("변경된 자료가 존재합니다.\n현재 자료를 저장하거나 화면을 다시 호출 하세요"); return; } UTIL.MsgI("목록화면고 동일한 배치의 데이터를 클립보드에서 가져옵니다\n(항목/분류/프로세스)"); var data = Clipboard.GetText(); var lines = data.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries); var dlg = UTIL.MsgQ($"{lines.Length} 개의 데이터가 있습니다.\n\n입력 할까요?"); if (dlg != DialogResult.Yes) return; var icnt = 0; var scnt = 0; var ecnt = 0; foreach (var line in lines) { var buf = line.Split(new char[] { '\t' }, StringSplitOptions.RemoveEmptyEntries); var item = buf[0].Trim(); if (item.isEmpty()) { ecnt += 1; continue; } var grp = buf.Length > 1 ? buf[1].Trim() : string.Empty; var prc = buf.Length > 2 ? buf[2].Trim() : string.Empty; //동일항목체크 if (this.dsJobReport.Common.Where(t => t.RowState != DataRowState.Detached && t.RowState != DataRowState.Deleted && t.memo.Equals(item) && t.svalue2.Equals(prc) && t.svalue.Equals(grp)).Any()) { scnt += 1; continue; } icnt += 1; var dr = this.dsJobReport.Common.NewCommonRow(); dr.svalue = grp; dr.svalue2 = prc; dr.memo = item; dr.wuid = FCOMMON.info.Login.no; dr.wdate = DateTime.Now; dr.grp = this.GroupCode; dr.code = makenewcode(); this.dsJobReport.Common.AddCommonRow(dr); } var msg = $"가져오기 결과 입니다\n\n추가:{icnt}\n중복:{scnt}\n오류:{ecnt}"; AR.UTIL.MsgI(msg); if (icnt > 0) RefreshTreeview(); } private void 전체삭제ToolStripMenuItem_Click(object sender, EventArgs e) { var dlg = UTIL.MsgQ("현재 목록 데이터를 삭제할까요?\n저장을 하면 최종 서버에 적용 됩니다"); if (dlg != DialogResult.Yes) return; var cnt = 0; while (bs.Count > 0) { bs.RemoveCurrent(); cnt += 1; } UTIL.MsgI($"{cnt}건의 자료가 삭제되었습니다\n저장버튼을 누르면 데이터베이스에 적용 됩니다"); } private void 클립보드에내보내기ToolStripMenuItem_Click(object sender, EventArgs e) { var sb = new System.Text.StringBuilder(); sb.AppendLine("항목\t분류\t프로세스"); var filterdata = this.dsJobReport.Common.Select(this.bs.Filter, this.bs.Sort); var cnt = 0; foreach (dsJobReport.CommonRow dr in filterdata) { if (dr.RowState == DataRowState.Deleted || dr.RowState == DataRowState.Detached) continue; cnt += 1; sb.AppendLine($"{dr.memo}\t{dr.svalue}\t{dr.svalue2}"); } Clipboard.SetText(sb.ToString()); AR.UTIL.MsgI($"{cnt}건의 자료가 클립보드에 입력되었습니다\n엑셀등의 프로그램에서 Ctrl+V 하세요"); } private void button1_Click_1(object sender, EventArgs e) { this.treeView1.ExpandAll(); } private void button3_Click_1(object sender, EventArgs e) { this.treeView1.CollapseAll(); } private void commonDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e) { //데이터그리드뷰 항목 더블클릭 if (this.FullName.isEmpty()) return; var drv = bs.Current as DataRowView; if (drv == null) return; var dr = drv.Row as dsJobReport.CommonRow; if (dr == null) return; Feedback(dr); } } }