C# ช่วยหน่อย!! ติดปัญหา comboBox 2 อัน คืออยากให้เลือก servicetype และ servicearea ช่วยดูให้หน่อยครับพี่น้อง
Concept คือ ถ้าเกิดเราเลือก ComboBox ที่ชื่อ ServiceType = Hardware อีก ComboBox ที่ชื่อ ServiceAreas จะโชว์แค่ Computer อย่างเดียว
และถ้าเกิดยังไม่เลือกServiceType ก่อน อยากให้ข้อมูลใน ServiceAreas ถูกซ่อน จะมีวิธีไหนบ้างครับ
รบกวนพี่ๆ น้องๆ ที่ครับ ขอบคุณล่วงหน้าครับ
โค้ดที่เอามาดัดแปลงก้อปัญหาดังนี้
รันโปรแกรม เกิด No mapping exits from object type System.Windows.Forms.ComboBox to a known managed provider native type.
Code (C#)
void fillcboServiceType()
{
SqlConnection db;
String strConnString;
strConnString = "server=(local)\\SQLEXPRESS;database=DBTest;Integrated Security=SSPI;";
db = new SqlConnection(strConnString);
try
{
string sql = " select * from tblServiceType";
SqlCommand SelectCommand = new SqlCommand(sql, db);
db.Open();
SqlDataAdapter dataadapter = new SqlDataAdapter(SelectCommand);//ประมวลผลคำสั่งเก็บไว้ที่ dataadapter
dataadapter.Fill(dataset, "tblServiceType");//เอาข้อมูลที่ได้จาก dataadapter มาไว้ใน datasetโดยเก็บไว้ที่ datataable ชื่อ type
if (dataset.Tables["tblServiceType"].Rows.Count > 0)
{
comboServiceType.DisplayMember = "ServiceTypeName"; //คอลัมที่ต้องการแสดง
comboServiceType.ValueMember = "ServiceTypeID"; //คอลัมที่เป็นคีย์
comboServiceType.DataSource = dataset.Tables["tblServiceType"];
}
db.Close();
db = null;
}
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
}
void fillcboServiceArea()
{
SqlConnection db;
String strConnString;
strConnString = "server=(local)\\SQLEXPRESS;database=DBTest;Integrated Security=SSPI;";
db = new SqlConnection(strConnString);
try
{
string sql = " select * from tblServiceAreas ";
SqlCommand SelectCommand = new SqlCommand(sql, db);
db.Open();
SqlDataAdapter dataadapter = new SqlDataAdapter(SelectCommand);//ประมวลผลคำสั่งเก็บไว้ที่ dataadapter
dataadapter.Fill(dataset, "tblServiceAreas");//เอาข้อมูลที่ได้จาก dataadapter มาไว้ใน datasetโดยเก็บไว้ที่ datataable ชื่อ type
if (dataset.Tables["tblServiceAreas"].Rows.Count > 0)
{
comboServiceArea.DisplayMember = "ServiceAreaName"; //คอลัมที่ต้องการแสดง
comboServiceArea.ValueMember = "ServiceAreaID"; //คอลัมที่เป็นคีย์
comboServiceArea.DataSource = dataset.Tables["tblServiceAreas"];
}
db.Close();
db = null;
}
catch (Exception ex)
{ MessageBox.Show(ex.Message); }
}
พอเลือก ComboBox เกิด The ConnectionString property has not been initialized.
Code (C#)
private void comboServiceTypeName_SelectedIndexChanged(object sender, EventArgs e)
{
string ServiceType = comboServiceType.SelectedValue.ToString();
DataSet ds = new DataSet();
String strConnString;
strConnString = "server=(local)\\SQLEXPRESS;database=DBTest;Integrated Security=SSPI;";
SqlConnection db = new SqlConnection(strConnString);
try
{
string sql = " select * from tblServiceType where ServiceTypeID=?servicetypeid ";
SqlCommand SelectCommand = new SqlCommand(sql, db);
db.Open();
SelectCommand.Parameters.Add(new SqlParameter("?servicetypeid", comboServiceType));
SqlDataAdapter dataadapter = new SqlDataAdapter(SelectCommand);
ds.Clear();
dataadapter.Fill(ds);
if (dataset.Tables["tblServiceType"].Rows.Count > 0)
{
comboServiceType.DisplayMember = "ServiceTypeName";
comboServiceType.ValueMember = "ServiceTypeID";
comboServiceType.DataSource = ds;
}
db.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void comboServiceArea_SelectedIndexChanged(object sender, EventArgs e)
{
string ServiceArea = comboServiceArea.SelectedValue == null ? "": comboServiceArea.SelectedValue.ToString();
string strConnString = null;
string strSQL = null;
DataSet ds = new DataSet();
try
{
SqlConnection db = new SqlConnection();
string sql = " select * from tblServiceAreas where ServiceAreaID=?serviceareaid ";
SqlCommand SelectCommand = new SqlCommand(sql, db);
db.Open();
SelectCommand.Parameters.Add(new SqlParameter("?serviceareaid", comboServiceArea));
SqlDataAdapter da = new SqlDataAdapter(SelectCommand);
ds.Clear();
da.Fill(ds);
if (dataset.Tables["tblServiceAreas"].Rows.Count > 0)
{
comboServiceArea.DisplayMember = "ServiceAreaName"; //คอลัมที่ต้องการแสดง
comboServiceArea.ValueMember = "ServiceAreaID"; //คอลัมที่เป็นคีย์
comboServiceArea.DataSource = dataset;
}
db.Close();
db = null;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Tag : C#
Date :
2014-05-13 22:11:39
By :
Zakariya
View :
3377
Reply :
10
อันดับแรก Source Code ผิดโครงสร้างครับ
ผิดที่จุดแรก การส่ง parameter ผิดรูปแบบ เปลี่ยนจาก ? เป็น @ ครับ
Code (C#)
// ผิดที่จุดแรก เปลี่ยนจาก ? เป็น @
string sql = " select * from tblServiceType where ServiceTypeID=@servicetypeid ";
SelectCommand.Parameters.Add(new SqlParameter("@servicetypeid", comboServiceType));
ผิดที่จุด 2 ผิดที่เอา object combobox ไปใส่ใน parameter select object
Code (C#)
// ผิดที่จุด 2 ตัวแปร comboServiceType เปลี่ยนเป็น string ServiceType นะครับ
string sql = " select * from tblServiceType where ServiceTypeID=@servicetypeid ";
SelectCommand.Parameters.Add(new SqlParameter("@servicetypeid", ServiceType));
ผิดที่จุด 3 ผิดที่ไม่มี connectionstring ในการ select serviceArea ประกาศเป็น null แต่ตอน new SqlConnection ไม่มี connectionString ครับ
Code (C#)
string ServiceArea = comboServiceArea.SelectedValue == null ? "" : comboServiceArea.SelectedValue.ToString();
string strConnString = null;
string strSQL = null;
// new โดยไม่มี connectionString จึงเกิด error "The ConnectionString property has not been initialized."
SqlConnection db = new SqlConnection();
ผิดที่จุดแรกกับจุด 2 ตัว comboBox ServiceArea แก้ให้เหมือน ServiceType ด้วย ไม่งั้นก็จะเจอ "No mapping exits from object type System.Windows.Forms.ComboBox to a known managed provider native type." อีกรอบ
เมื่อแก้เสร็จแล้ว จะมี error อีก ผิดที่โครงสร้าง จุดที่ 4 แต่จุดนี้เดี๋ยวเย็นๆ มาตอบ เพราะว่าต้องเปลี่ยนโปแรกรมใหม่หมดเลย เป็นการเขียนโปรแกรมที่ผิดพลาดครับ ผิดโครงสร้างการทำงาน ผิด dataFlow ผิด dataStructure พูดง่ายๆ ต้องเขียนใหม่หมดครับ
Date :
2014-05-14 10:47:43
By :
gunnermontana
ลองดูนะครับ พึ่งจะว่างเลยกลับมาเขียนให้
ทดสอบสร้าง Form เพิ่ม ComboBox เข้าไป 2 อัน แล้ววาง Code ดังนี้
Code (C#)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// เปิดฟอร์มมา ทำการ Binding เข้าไปยัง comboServiceType
string cmdText = "select * from tblServiceType";
try
{
// ใช้งาน Function ComboBoxDataBinding เพื่อสะดวกในการใช้ และ reused code ได้ ลดความซับซ้อน
ComboBoxDataBinding(comboServiceType, cmdText, "ServiceTypeName", "ServiceTypeID");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// ถ้ามีการเปลี่ยนแปลงชุดข้อมูลของ ServiceType ค่าที่อยู่ใน comboBoxServiceArea ต้องเปลี่ยนไปด้วย
private void comboServiceType_SelectedIndexChanged(object sender, EventArgs e)
{
// รับค่าที่เปลี่ยนแปลงเข้ามาจาก ServiceType
string serviceTypeID = this.comboServiceType.SelectedValue.ToString();
// นำค่า serviceTypeValue ไปค้นหาข้อมูล serviceArea
string cmdText = "select * from tblServiceAreas where ServiceTypeID = @ServiceTypeID";
try
{
// ส่งเข้าไปยัง ComboBoxDataBinding โดยมี params list ของข้อมูล ServiceTypeID ประกอบอยู่ด้วย
ComboBoxDataBinding(this.comboServiceArea, cmdText, "ServiceAreaName", "ServiceAreaID", serviceTypeID);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// Function BindConnection สำหรับดึง SqlConnection
// เปลี่ยน ConnectionString ที่นี้ที่เดียว จะได้ไม่สับสน เดี๋ยวพิมพ์ผิด พิมพ์ถูก ลดความซับซ้อนของโปรแกรมลง
private SqlConnection BuildConnection()
{
string connectionString = "server=(local)\\SQLEXPRESS;database=DBTest;Integrated Security=SSPI;";
return new SqlConnection(connectionString);
}
// สร้าง Function ComboBoxDataBindging เพื่อสะดวกในการส่งค่า comboBox หลายๆ ชุด เข้ามาทำงานผ่าน Function นี้แทน
// รับค่า object control comboBox
// รับค่า cmdText เป็นคำสั่ง select sql
// รับค่าการ Binding ให้กับ comboBox กำหนดเข้ามาเป็นชุด displayMember และ valueMember
private void ComboBoxDataBinding(ComboBox comboBox, string cmdText, string displayMember, string valueMember)
{
// ส่งค่าผ่านไปยัง Overload Function เดียวกัน โดยไม่ส่ง parameter กำหนดเป็น null
ComboBoxDataBinding(comboBox, cmdText, displayMember, valueMember, null);
}
// สร้าง Overload Function เพิ่มกรณีมีการกำหนดค่า Parameter ให้กับคำสั่ง sql
// รับค่าเป็น params list ของ string สามารถกำหนดได้มากกว่า 1 ตัวแปร
// !!ข้อควรระวัง Function นี้ ยังสร้างไม่สมบูรณ์ อาจเกิดข้อผิดพลาดได้หากผู้ใช้งาน กำหนดค่า cmdText โดยมี parameter ที่ไม่สอดคล้องกับค่า params list ที่กำหนดค่าเข้ามา
// !!ต้องเข้าใจว่าถ้ามีการกำหนดค่า paramter ให้กับ cmdText จะต้องส่งค่าข้อมูลของ list ให้เท่ากันกับคำสั่ง sql
private void ComboBoxDataBinding(ComboBox comboBox, string cmdText, string displayMember, string valueMember, params string[] list)
{
try
{
DataTable dataTable = null;
// ดึงค่า SqlConnection มาจาก Function BindConnection
using (SqlConnection sqlConnection = BuildConnection())
// กำหนด cmdText รับมาจาก Function เข้าสู่ SqlCommand
using (SqlCommand sqlCommand = new SqlCommand(cmdText, sqlConnection))
using (SqlDataAdapter sqlDataAdapter = new SqlDataAdapter(sqlCommand))
{
DataSet dataSet = new DataSet();
sqlConnection.Open();
// ตรวจสอบว่ามีการกำหนด parameter เข้ามาหรือไม่
if (list != null)
{
// มี parameter อยู่ในคำสั่ง cmdText ให้แยก string ออกด้วยตัวอักษร @
string[] parameters = cmdText.Split('@');
for (int i = 0; i < list.Length; i++)
{
// วนค่าเข้าไปและกำหนด paramter ตามจำนวนที่รับเข้ามายัง list
// ค่า parameterName อ่านมาจากคำสั่ง cmdText ที่ถูกแบ่งออกมา แต่ว่าจะเริ่ม index 1 (เพราะ index 0 คือคำสั่ง sql ด้านหน้า)
// ค่า value มาจากค่า params list ที่กำหนดเข้ามา อ่านตามค่า index ที่พบ
sqlCommand.Parameters.Add(new SqlParameter("@" + parameters[i + 1].Trim(), list[i]));
}
}
sqlDataAdapter.Fill(dataSet);
sqlConnection.Close();
if (dataSet.Tables.Count > 0)
{
// ไม่ต้องอ้างชื่อตารางก็ได้ เนื่องจาก dataSet มีเพียง 1 Table แล้วเป็น Table ที่เรารู้อยู่แล้ว
dataTable = dataSet.Tables[0];
}
}
// ได้ dataSet กลับมา นำมา Bind ให้กับ ComboServiceArea
if (dataTable != null)
{
comboBox.DisplayMember = displayMember; //คอลัมที่ต้องการแสดง
comboBox.ValueMember = valueMember; //คอลัมที่เป็นคีย์
comboBox.DataSource = dataTable; // เอา dataTable มาต่อเข้ากับ comboBox
}
}
catch (Exception ex)
{
throw ex;
}
}
}
ประวัติการแก้ไข 2014-05-14 16:42:09
Date :
2014-05-14 16:39:15
By :
gunnermontana
รบกวนพี่อีกนิดหนึ่งน่ะพี่
คือถ้า Run Program เราอยากให้ ComboBox มีข้อความดังภาพ
และ ComboBox ของ ServiceArea เป็น Disable พอเราเลือก ServiceType เป็น Hardware, Software, Network
ให้ ServiceArea เป็น Enable เราจะเพิ่มเติมตรงไหน
Date :
2014-05-14 21:52:48
By :
Zakariya
แก้ไข method ดังนี้
Code (C#)
private void Form1_Load(object sender, EventArgs e)
{
// เปิดฟอร์มมา ทำการ Binding เข้าไปยัง comboServiceType
string cmdText = "select 0 as ServiceTypeID, '--Select Service Type--' as ServiceTypeName from sys.all_objects " +
"union " +
"select * from tblServiceType";
try
{
// ใช้งาน Function ComboBoxDataBinding เพื่อสะดวกในการใช้ และ reused code ได้ ลดความซับซ้อน
ComboBoxDataBinding(comboServiceType, cmdText, "ServiceTypeName", "ServiceTypeID");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
// ถ้ามีการเปลี่ยนแปลงชุดข้อมูลของ ServiceType ค่าที่อยู่ใน comboBoxServiceArea ต้องเปลี่ยนไปด้วย
private void comboServiceType_SelectedIndexChanged(object sender, EventArgs e)
{
// รับค่าที่เปลี่ยนแปลงเข้ามาจาก ServiceType
string serviceTypeID = this.comboServiceType.SelectedValue.ToString();
// นำค่า serviceTypeValue ไปค้นหาข้อมูล serviceArea
string cmdText = "select * from " +
"(" +
"select 0 as ServiceAreaID, '--Service Area--' as ServiceAreaName, 0 as ServiceTypeID from sys.all_objects " +
"union " +
"select * from tblServiceAreas " +
") areas " +
"where areas.ServiceTypeID = @ServiceTypeID";
try
{
// ส่งเข้าไปยัง ComboBoxDataBinding โดยมี params list ของข้อมูล ServiceTypeID ประกอบอยู่ด้วย
ComboBoxDataBinding(this.comboServiceArea, cmdText, "ServiceAreaName", "ServiceAreaID", serviceTypeID);
// อ้างอิงค่า serviceTypeID ตรวจสอบว่าเป็น 0 ให้ทำการปิด comboServiceArea
this.comboServiceArea.Enabled = (Convert.ToInt32(serviceTypeID) != 0);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
เทคนิคการเพิ่ม Dummy Sql เป็นการสร้างข้อมูลหลอกขึ้นมาตอน Run Time โดยใช้หลักการ Union Table เข้าด้วยกัน วิธีนี้เป็นวิธีที่อาจจะไม่ดีพอ แต่ก็ไม่กระทบกับการทำงานของโปรแกรมหลัก โดยการพลักภาระไปที่คำสั่ง Sql โดยตรง เป็นเทคนิคที่นิยมใช้กัน แต่ถ้าเจอตารางที่มีความซับซ้อนสูง อาจจะไม่เลือกใช้วิธีดังกล่าว แต่จะใช้วิธีการต่อ data จาก object ที่สร้างขึ้นมาเอง โดยใน object ตัวนั้นจะมีโครงสร้างทั้งการ Binding มาจากฐานข้อมูลและสามารถเพิ่มข้อมูล Dummy เข้าไปเองได้ กรณีหลังนี้ต้องมีการวาง OO ให้ถูกหลักก่อน ถึงจะทำได้ครับ
Date :
2014-05-14 22:49:53
By :
gunnermontana
จากโค้ดดังกล่าว...
เกิด The text data type cannot be selected as DISTINCT because it is not comparable.
เกิดจากอะไร ไม่สามารถ เลือกข้อมูลได้ DISTINCT เพราะไม่สามารถ comparable. มองไม่ออกว่าจะแก้ตรงไหน.
ผิดตรงที่...
Code (C#)
string cmdText = "select 0 as ServiceTypeID, '--Select Service Type--' as ServiceTypeName from sys.all_objects " +
"union " +
"select * from tblServiceType";
...รึปล่าวครับ
พี่ครับแล้วตรง sys.all_objects มันคืออะไรหรอครับ ไม่เคยเจอด้วย
Date :
2014-05-15 08:22:19
By :
Zakariya
งั้นก็ลองปรับคำสั่งเป็น Distinct ดูก่อนครับ
Code (C#)
string cmdText = "select DISTINCT 0 as ServiceTypeID, '--Select Service Type--' as ServiceTypeName from sys.all_objects " +
"union " +
"select * from tblServiceType";
ส่วน sys.all_object มันคือ table ที่ Sql Server ได้สร้างขึ้นให้ เอาไว้จัดการงานภายในจำพวก table column หรือ schema ของฐานข้อมูลที่เราสร้างขึ้น คล้ายๆ คำสั่ง internal ของ sql server เอง แต่ที่เราเอามาใช้เพื่อทำให้เกิดตารางรองรับการดึงค่าเท่านั้นเอง เพราะว่าค่า static ที่เรากำหนดลงไปเอง
แต่จริงๆ มันไม่ต้องอ้างก็ได้ครับ ลองดูว่าผ่านมั้ย พอดีเขียนจนเคยชิน
Code (C#)
string cmdText = "select 0 as ServiceTypeID, '--Select Service Type--' as ServiceTypeName " +
"union " +
"select * from tblServiceType";
แก้อีกคำสั่งนึงไปด้วยกันเลย
Code (C#)
string cmdText = "select * from " +
"(" +
"select 0 as ServiceAreaID, '--Service Area--' as ServiceAreaName, 0 as ServiceTypeID " +
"union " +
"select * from tblServiceAreas " +
") areas " +
"where areas.ServiceTypeID = @ServiceTypeID";
ประวัติการแก้ไข 2014-05-15 21:44:18
Date :
2014-05-15 21:43:51
By :
gunnermontana
ลองเช็คข้อมูลในฐานข้อมูลดูด้วยนะครับ เพราะที่ทดสอบแล้วผ่านก็ทำแค่ตามโจทย์ที่บอกมาแค่นั่น ลองเอาคำสั่ง copy ไป run ดูที่ sql studio management ดูด้วยว่าติดหรือไม่นะครับ เพราะถ้าไม่ลองรันให้ผ่านดูก่อนก็คงช่วยอะไรไม่ได้นะครับ น้องต้องมีความพยายามบ้างแล้วนะครับ ตรวจสอบ source code อาจประกาศตัวแปรไม่ตรงกันหรืออะไรก็แล้วแต่
พี่ถือว่า source code ที่พี่ปล่อยออกไป run ผ่านหมดทุกขั้นตอนแล้ว จากจุดนี้จะไม่เข้ามาดูและแก้ไขให้แล้วครับ ขอปิดงาน
Date :
2014-05-15 22:50:10
By :
gunnermontana
Load balance : Server 00