PDA

View Full Version : سوال: خواندن داده ستونهایی از گریدویو که کاربر انتخاب کرده



MasoudAdmin
یک شنبه 13 شهریور 1401, 21:13 عصر
با سلام
من یک برنامه دارم که فایل اکسل رو میخونه و اطلاعات ستون هاش رو داخل جدول اصلی اطلاعات نمایش میده و فیلدهای ستون اکسل رو هم داخل یک گرید دیگه نمایش میدم. حالا میخوام وقتی فیلدها رو از گریدی که ستون های اکسل رو داره تیک میخوره رو بخونه و سپس ردیف های جدول اصلی رو بر اساس فیلدهای انتخاب شده از گریدی که ستون های فایل اکسل رو تیک زده بخونه و برای ردیف بعدی متن قبلی رو پاک و برای ردیف بعدی جدول اصلی دوباره اطلاعات رو بخونه الی آخر.
تصویر برنامه رو می گذارم. امیدوارم که متوجه شده باشید. ممنون میشم کمک کنید.
154008
برای مثال بر اساس تصویری که فرستادم مواردی که تیک خوردند بیاد جدول اصلی رو بخونه و ردیف به ردیف باید تو اون TextBox باید اینجوری باشه
تست1 تست2 تست4 11111111111
واسه ردیف دوم مقدار قبلی توی TextBox رو پاک کنه و مقدار جدید این میشه:
تست8 تست9 تست11 22222222222

الی آخر

mmbguide
دوشنبه 14 شهریور 1401, 19:31 عصر
سلام

الان مشکل شما کجاست؟ کنترل Grid چه در خود ویندوز و چه کامپوننت ها دارای رویدادهای زیادی هستند. برای مثال شما میونید در رویداد SelectedIndexChanged مقادیر RowIndex و ColumnIndex را دریافت کنید و در ردیف جاری مقدار یک سلول را بخوانید و ....

https://stackoverflow.com/questions/53781635/asp-net-gridview-selected-index-changed-not-firing

mazoolagh
سه شنبه 15 شهریور 1401, 08:12 صبح
سلام و روز خوش
الان که ادیت کردین مشخص شد خواسته تون چی هست.

همیشه مسائل رو ساده کنین.
اول فرض کنین که قرار هست کارها غیرخودکار و مثلا در یک button click انجام بشه؛ پس یک روتین مینویسین (مثلا به اسم calc) که کارها رو انجام بده و در اون button click این روتین رو سدا میزنین.
اگر همه چیز درست بود اونوقت میرین سراغ این که در چه رویداد (یا رویدادهایی) باید این روتین رو سدا بزنین تا کل پروسه خودکار انجام بشه.

قدم اول این هست که در گرید اطلاعات (فرضا اسمش persons_grid) چجوری به دیتا هر سلول از سطر focus شده دسترسی پیدا کنیم.

از رو تصویر پیوست مشخص هست که از کمپوننت devexpress grid control استفاده کردین و این کار رو راحت میکنه:
کافی هست از متد getfocuseddatarow(column_name) استفاده کنین.

قدم بعدی این هست که از گرید دست راست (فرضا اسمش fields_grid) سطرهایی رو که چک خوردن پیدا کنین.
ظاهرش اینجور نشون میده که datagridview استاندارد استفاده شده.
بسته به این که این گرید bound یا unbound روش تفاوت میکنه؛ ولی روشی که برای unbound استفاده میکنین برای bound هم قابل استفاده است ولی برعکسش اینجور نیست.

اگر bound هست (مثلا به دیتاتیبل fields_datatable) که خیلی راحت با متد select روی دیتاتیبل یک کالکشن از سطرهای تیک خورده رو در دست دارین:

fields_datatable.select("select")

اگر unbound هست باید در تک تک سطرهای fields_grid بچرخین و مقدار ستون select رو چک کنین.

برای کنار هم گذاشتن دیتا سلولها و نمایش اون در تکسباکس میونین از queue استفاده کنین:
در حلقه ای که روی سطرهای تیک خورده میچرخه مقدار column رو به عنوان column_name در getfocuseddatarow استفاده میکنین و دیتا رو در queue میریزین.

دست آخر هم مقادیر queue رو join میکنین و نتیجه رو در تکسباکس میریزین.

وقتی همه این ها رو انجام دادین و تست کردین و نتیجه درست بود میرین سروقت خودکار کردن پروسه.

برای persons_grid کافی هست از رویداد focusedrowchnged استفاده کنین که در گریدهای devexpress هست.

برای fields_grid هم لازمه به محض تغییر وضعیت هر چکباکس، calc اجرا بشه وگرنه باید در persons_grid سطر فوکوس شده رو عوض کنین و دوباره برگردین که ایراد محسوب میشه.
این یه کم پیاده سازیش مشکلتر هست و پیشنهاد میکنم اول اینها رو که گفته شد انجام بدین، بعد این رو هم اگر نیاز به کمک داشتین مطرح کنین تا توضیح بدم.

MasoudAdmin
سه شنبه 15 شهریور 1401, 10:12 صبح
با سلام
شرمنده من متوجه مواردی که عرض کردید رو نشدم. می تونم سورس کدم رو بگذارم و نمونه فایل اکسلم.
زحمتش بکشید کدش رو تکمیل کنید.:افسرده:
خیلی لطف می کنید اگر تو این موضوع کمکم کنید.
اگر ممکن هست ایمیلتون رو داشته باشم واستون ایمیل کنم.

mazoolagh
چهارشنبه 16 شهریور 1401, 11:16 صبح
سلام دوباره
من سعی کردم ساده و دقیق توضیح بدم تا راحت بتونین پیاده اش کنین.
فعلا نیازی نیست چیزی رو پیوست کنین، لازم شد یک نمونه پیوست میکنم.

شما کدوم قسمت رو مشکل دارین، همون رو بگین. بعد مرحله به مرحله جلو میریم.

MasoudAdmin
چهارشنبه 16 شهریور 1401, 20:41 عصر
این کد خواند فایل با زدن دکمه انتخاب فایل


private void btnChooseFile_Click(object sender, EventArgs e)
{
Excel.Application excel = new Excel.Application();
openFileDialog1.Filter = "Excel Files(*.xls;*.xlsx)|*.xls;*.xlsx";
DialogResult DR = openFileDialog1.ShowDialog();
if (DR == DialogResult.OK)
{
string FilePath = openFileDialog1.FileName;
this.txtPathFile.Text = openFileDialog1.FileName;
Extension = Path.GetExtension(this.txtPathFile.Text.Trim());
File_Body = File.ReadAllBytes(this.txtPathFile.Text);
Excel.Workbook workbook = excel.Workbooks.Open(FilePath);
this.cmbListTables.Items.Clear();
foreach (Excel.Worksheet work_sheet in workbook.Worksheets)
{
this.cmbListTables.Items.Add(work_sheet.Name);
}
raddgvData.DataSource = null;
this.dgvListColums.Rows.Clear();
}
}

این کد کلید واکشی اطلاعات



private void btnReadDataFromExcel_Click(object sender, EventArgs e)
{
if(this.cmbListTables.Text.Trim()=="" || this.txtPathFile.Text.Length==0)
{
FarsiMessegeBox.Show("کاربر گرامی جدولی جهت واکشی اطلاعات فایل اکسل انتخاب نشده است", "توجّه", FMessegeBoxButtons.Ok, FMessegeBoxIcons.Exclamtion, FMessegeBoxDefaultButton.button1);
raddgvData.DataSource = null;
this.dgvListColums.Rows.Clear();
}
else
{


try
{
this.dgvListColums.Rows.Clear();
raddgvData.DataSource = null;
String constr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + this.txtPathFile.Text + ";Extended Properties='Excel 12.0 XML;HDR=YES;';";
OleDbConnection con = new OleDbConnection(constr);
OleDbCommand oconn = new OleDbCommand("Select * From [" + this.cmbListTables.Text + "$]", con);
con.Open();
OleDbDataAdapter sda = new OleDbDataAdapter(oconn);
DataTable data = new DataTable();
sda.Fill(data);
this.raddgvData.DataSource = data;
foreach (GridViewDataColumn item in raddgvData.Columns)
{
this.dgvListColums.Rows.Add(item.Index, item.Name);
}
}
catch
{
FarsiMessegeBox.Show("کاربر گرامی، خواندن فایل اکسل با شکست مواجه شد.لطفا از بسته بودن فایل اکسل مورد نظر مطمئن باشید"+"\n\r"+"در صورت اطمینان از بسته بودن فایل اکسل، احتمالا فایل دارای مشکل می باشد.لطفا فایل مورد نظر را بررسی فرمایید", "توجّه", FMessegeBoxButtons.Ok, FMessegeBoxIcons.Exclamtion, FMessegeBoxDefaultButton.button1);
}
}
}




حالا میخوام وقتی کلید ارسال پیامک رو زدم بر اساس جدول لیست ستون های فایل اکسل، ستون هایی که تیک میخورند بره سراغ جدول اصلی اطلاعات و بر اساس تیک های ستون ها، اطلاعات جدول اصلی را بخواند و ردیف به ردیف بره تا آخر.

ممنون

mazoolagh
شنبه 19 شهریور 1401, 11:46 صبح
به این کدها نیازی نیست و ربطی به پرسش شما هم نداره، در واقع خواسته شما کار ساده ای هست ولی نیاز به دقت داره.
اینها فقط برای خوندن لیست شیت ها و فیلدها و ... هست که قبلا انجام دادین.
البته چند مورد به چشمم خورد که الان مهم نیست ولی در پایان یادآوری کنین بهتون بگم چون برنامه تون به اشکال اساسی میخوره.

شما برای شروع یک باتن روی فرم بندازین و در رخداد click اون کد زیر رو بنویسین (حواستون به case دستورها باشه! و شاید ویرایش جزئی هم بخواد)
با فرض اینکه ستون های dgvListColums بترتیب Index,ColumnName,Selected باشن :

list<string> values = new list<string>() ;
foreach (datagridviewrow column in dgvListColums.rows)
{
if ( convert.toboolean( column.cells["Selected"].value ) )
{
values.add( raddgvData.getfocuseddatarow()[column.cells["ColumnName"].value.tostring()].tostring() ) ;
}
}
string result = string.join("/" , values.toarray() ) ;

حالا این result رو هر کاری خواستین باهاش میکنین.

برای خودکار کردن پروسه (با تغییر سطر raddgvData و تغییر وضعیت چک باکسهای dgvListColums) هم قبلا دقیق توضیح دادم که چکار باید بکنین.

MasoudAdmin
شنبه 19 شهریور 1401, 15:44 عصر
با سلام.
خیلی ممنون و سپاسگذارم. چون 10 روی نیستم و به سورسم دسترسی ندارم، نمی تونم کدها رو تست کنم و ادامش رو از راهنمایی های شما استفاده کنم. حتما بعد از برگشتم خبرش رو بهتون میدم.
بازم خیلی لطف کردید.

MasoudAdmin
پنج شنبه 31 شهریور 1401, 17:46 عصر
با سلام. ببخشید چند روزی نبودم به کدهام دسترسی نداشتم.
الان این کد گذاشتم ولی یه مشکلی هست. این getfocuseddatarow رو نمیشناسه. این موارد هم وجود دارند:

using Telerik.WinControls;
using Telerik.WinControls.UI;

تصویر مشکل:
154031
ممنون میشم راهنمایی بفرمایید.

mazoolagh
چهارشنبه 06 مهر 1401, 10:51 صبح
سلام دوباره
تو پست 3 نوشته بودم که "از رو تصویر پیوست مشخص هست که از کمپوننت devexpress grid control استفاده کردین" ،
بر همین اساس هم از رخدادها و متدها این کنترل استفاده کردم،و شما هم منو از اشتباه در نیاوردین.

الان میبینم که از telerik grid استفاده کردین.
مهم نیست چون اصول کار یکی هست، فقط همون خط values.add باید ویرایش بشه.
سر فرصت داکیومنت هاش رو نگاه میکنم و کد ش رو میگم.

MasoudAdmin
چهارشنبه 06 مهر 1401, 16:47 عصر
سلام. ببخشید. بله از Telerik استفاده کردم.
منتظر داکیومنت هاتون می مونم.
بازم سپاس فراوان.

mazoolagh
پنج شنبه 07 مهر 1401, 11:17 صبح
با توجه به مستندات گرید تلریک (https://docs.telerik.com/devtools/winforms/controls/gridview/cells/accessing-and-setting-the-currentcell)

values.add( raddgvData.currentrow.cells[column.cells["ColumnName"].value.tostring()].value.tostring() );

این کد رو چک کنین اگه مشکلی بود خبر بدین.

برای خودکار کردن پروسه هم باید رویداد مربوط رو استفاده کنین، من نتونستم با جستجو پیدا کنم و کیفیت مستندات تلریک واقعا پایین و ناقص هست گویا.
ولی بطور منطقی باید چیزی شبیه currentrowchanged باشه. تو لیست eventهای کنترل رو که بگردین پیدا میشه که دقیقا چی هست (در همون محیط طراحی فرم)

MasoudAdmin
شنبه 09 مهر 1401, 19:54 عصر
سلام. ممنون


private void raddgvData_CurrentRowChanged(object sender, CurrentRowChangedEventArgs e)
{
List<string> values = new List<string>();
foreach (DataGridViewRow column in dgvListColums.Rows)
{
if (Convert.ToBoolean(column.Cells["Selected"].Value))
{
values.Add(raddgvData.CurrentRow.Cells[column.Cells["ColumnName"].Value.ToString()].Value.ToString());
}
}
string result = string.Join("/", values.ToArray());
MessageBox.Show(result);
}


متاسفانه خطا داره
تصویرش
154038
:افسرده::ناراحت:

mazoolagh
یک شنبه 10 مهر 1401, 08:00 صبح
از پست 7:

با فرض اینکه ستون های dgvListColums بترتیب Index,ColumnName,Selected باشن :

یا اسم ستونها رو طبق کد عوض کنین، و یا کد رو متناظر با طراحی ویرایش کنین.

MasoudAdmin
یک شنبه 10 مهر 1401, 18:24 عصر
ممنون.:تشویق: بعضی وقتا یه چیز خیلی ساده که جلوی چشم آدم هست متوجه نمیشه. بله اسمش رو درست کردم اوکی شد.
فقط اینکه با رویداد raddgvData_CurrentRowChanged وقتی روی ردیف جدول اصلی کلیک می کنم میره مواردی که در اون جدول فیلدهایی که تیک خوردن رو نمایش میده. چجوری بیام این مورد رو جوری انجام بدم که از سطر اول جدول اصلی شروع کنه و تا انتهای لیست بره و مواردی که تیک خورده رو نمایش بده.
یک کلید گذاشتم روی فرم و همین کدی که تو رویداد raddgvData_CurrentRowChanged رو داشتم با حلقه for گذاشتم همش داره فقط همون ردیف اول رو میاره و سراغ ردیف های بعدی نمیره.



private void btnSendSms_Click(object sender, EventArgs e)
{
for (int i = 0; i < this.raddgvData.RowCount; i++)
{
List<string> values = new List<string>();
foreach (DataGridViewRow column in dgvListColums.Rows)
{
if (Convert.ToBoolean(column.Cells["ColumnNameCheck"].Value))
{
values.Add(raddgvData.CurrentRow.Cells[column.Cells["ColumnName"].Value.ToString()].Value.ToString());
}
}
string result = string.Join("/", values.ToArray());
MessageBox.Show(result);
}
}


ممنون میشم اینم راهنمایی کنید.

mazoolagh
دوشنبه 11 مهر 1401, 10:05 صبح
1- خب الان شما درون حلقه کی از اندیس i استفاده کردین؟
همون currentrow رو کپی کردین و مشخصه که فقط همون row برمیگرده!
بجاش باید rows[i] رو بگذارین (منطقا باید همین rows باشه، ولی یک احتمال خیلی ضعیف هم درنظر بگیرین که تلریک یک اسم دیگه گذاشته باشه - اگر خطا داد داکیومنتهاش رو چک کنین یا از intellisense خود vs کمک بگیرین)

2- این که messagebox رو درون حلقه بگذارین خیلی آزاردهنده است!
فکر کنم منظورتون فقط چک کردن کد باشه،
پس یا همه resultها رو با crlf به هم بچسبونین و فقط یک messagebox بیرون حلقه بذارین،
یا از console.writeline استفاده کنین.
اگر برای نمایش بهش احتیاج دارین شاید بهتر باشه یک ستون به گرید اضافه کنین یا اونها رو در یک listbox بریزین.

3- قبلا هم اشاره کردم، دوباره یادآوری میکنم که:
این روشی که برای خوندن لیست شیت های فایل اکسل استفاده کردین (office.interop) اگر کدتون همینی هست که در پست 6 گذاشتین اشکال اساسی داره!
فعلا بقیه کارها رو تکمیل کنین ولی یادتون باشه برگردین برای این مورد.

MasoudAdmin
دوشنبه 11 مهر 1401, 20:28 عصر
سلام.
در خصوص بند یک بله Rows[i] حل شد.
در خصوص بند دو بله واسه چک کردنم بود.
در خصوص بند سه چندجا جستجو کردم این مورد رو هم تو سایت stackoverflow پیشنهاد داده بود از این روش استفاده کنم. بازم اگر روش بهینه تر و بهتری دارید ممنون میشم لطف کنید.

mazoolagh
سه شنبه 12 مهر 1401, 15:42 عصر
سلام دوباره


هر بار که
Excel.Application excel = new Excel.Application();
رو اجرا میکنین یک پروسس اکسل باز میشه و در حافظه باقی میمونه و با بستن برنامه هم هنوز در حال اجراست.


و داکیومنتی هم که با
Excel.Workbook workbook = excel.Workbooks.Open(FilePath);
باز میکنین، باز میمونه و دسترسی های بعدی به اون read only میشه.


هم باید workbook رو ببندین و هم از اکسل بیرون بیاین:
workbook.close();
excel.quit();


بهتره office.interop dispose excel رو گوگل کنین.

mazoolagh
سه شنبه 12 مهر 1401, 15:47 عصر
راه دیگه اینه که اصلا از office.interop استفاده نکنین،
بجاش همون oledbconnection رو که باز کردین، از متد GetOleDbSchemaTable استفاده کنین.
برای نمونه کد هم همین رو گوگل کنین.