2010-10-13 62 views
6

Tôi có cơ sở dữ liệu này, không phải của thiết kế của tôi, nhưng tôi phải làm việc với nó, có chứa một bảng như sau:Làm thế nào để hiển thị giá trị enum trong cột datagridview

tài sản
 
id | Name  | status | ... 
-----+------------+----------+------ 
1 | Product1 | 2  | ... 
2 | Product2 | 2  | ... 
3 | Product3 | 3  | ... 
... | ...  | ...  | ... 

Tình trạng đề cập đến một enum nơi

 
0 = Invalid 
1 = Dev 
2 = Activ 
3 = Old 

Khi tôi hiển thị điều này trong chế độ xem dữ liệu chỉ đọc, tôi muốn người dùng thấy tên của enum (Dev, Activ, ...) hoặc mô tả thay vì giá trị số. Datagridview được ràng buộc với một datatable mà đến từ một DAL, một lần nữa không phải thiết kế của tôi, vì vậy tôi không thể thực sự thay đổi datatable. Cách duy nhất tôi thấy làm thế nào để làm điều đó là bằng cách lắng nghe sự kiện datagridview.CellFormating nơi tôi đặt mã này:

private void dataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) 
{ 
    if (e.ColumnIndex == 3) // column of the enum 
    { 
     try 
     { 
      e.Value = getEnumStringValue(e.Value); 
     } 
     catch (Exception ex) 
     { 
      e.Value = ex.Message; 
     } 
    } 
} 

này hoạt động tốt, ngoại trừ rằng nếu tôi có khoảng 1k (không phải là nhiều) hoặc nhiều mục , phải mất mãi mãi ... Có cách nào tốt hơn để thực hiện việc này không?

--- Chỉnh sửa ---
Điều này làm việc tốt vì nó là, vấn đề của tôi là nếu có hơn 1000 hàng trong datatable, phải mất bao giờ hết. Vấn đề là sự kiện CellFormating kích hoạt cho mọi cột, ngay cả những cái không cần nó. Giả sử tôi hiển thị 15 cột và có 1000 hàng, sau đó sự kiện đó kích hoạt 15 000 lần ...

Có cách nào tốt hơn so với sử dụng Sự kiện CellFormating không? Hoặc có cách nào để thêm Sự kiện CellFormating vào chỉ một Cột không? Hay cái gì ?

+0

@Oliver, K = thousand; 1K = 1,000 – Brad

+0

Nếu mô tả trạng thái được xác định trong một bảng riêng biệt thì bạn có thể tham gia trên bảng đó và trả về mô tả như một phần của dữ liệu bạn muốn hiển thị. Đây là loại cơ sở dữ liệu điều có nghĩa là để làm, và tôi thấy nó kỳ quặc rằng các giải pháp đề xuất liên quan đến việc lặp qua các kết quả trả về bởi cơ sở dữ liệu. Tất nhiên nhận xét này sẽ trở thành tranh luận nếu dữ liệu yêu cầu không có trong cơ sở dữ liệu hoặc bạn không thể tự chèn nó. –

+0

không ... thật đáng buồn là các giá trị cho trạng thái không nằm trong DB (không phải thiết kế của tôi) –

Trả lời

7

Tôi sẽ không làm điều đó trên CellFormatting. Tôi sẽ tấn công DataTable. Tôi sẽ thêm một hàng có loại enum, và vòng lặp thông qua bảng và thêm các giá trị. Một cái gì đó như thế này:

private void Transform(DataTable table) 
    { 
     table.Columns.Add("EnumValue", typeof(SomeEnum)); 
     foreach (DataRow row in table.Rows) 
     { 
      int value = (int)row[1]; //int representation of enum 
      row[2] = (SomeEnum)value; 
     } 
    } 

Sau đó, trong DataGridView của bạn chỉ ẩn cột có đại diện số nguyên enum của bạn.

+1

Vâng, Tôi nghĩ về điều đó, nhưng vấn đề của tôi là DataTable không đến từ tôi, và tôi sợ những gì có thể xảy ra sau này trong mã nếu tôi thêm một cột ... Ngoài ra, sẽ làm như thế này lên ? –

+2

Có, nó sẽ tăng tốc độ bởi vì điều này sẽ xảy ra trước khi bạn liên kết, và bạn sẽ không cần phải gây rối với tất cả các sự kiện định dạng. Bạn có thể thử nhân bản DataTable trước khi bạn làm điều này, theo cách đó, bản gốc không bị rối tung lên. Tôi vẫn nghĩ nó sẽ nhanh hơn. Cho nó một shot. – BFree

+0

Tôi sẽ cố gắng ... sao chép các Datatable, thêm một cột mới, làm bất kỳ hình thức khác, và sau đó ràng buộc nó với DGV ... Cảm ơn –

0

Hiện tại tôi không hiểu ý bạn là gì với 1k mục.

Nhưng những gì bạn phải làm chỉ là tạo ra các enum cho chính mình thích:

public enum States 
{ 
    Invalid = 0, 
    [Description("In developement")] 
    Dev, 
    Activ, 
    Old, 
    ... 
} 

Và trong trường hợp định dạng của bạn của bạn, bạn gọi hàm này

/// <summary> 
/// Gets the string of an DescriptionAttribute of an Enum. 
/// </summary> 
/// <param name="value">The Enum value for which the description is needed.</param> 
/// <returns>If a DescriptionAttribute is set it return the content of it. 
/// Otherwise just the raw name as string.</returns> 
public static string Description(this Enum value) 
{ 
    if (value == null) 
    { 
     throw new ArgumentNullException("value"); 
    } 

    string description = value.ToString(); 
    FieldInfo fieldInfo = value.GetType().GetField(description); 
    DescriptionAttribute[] attributes = 
     (DescriptionAttribute[]) 
    fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false); 

    if (attributes != null && attributes.Length > 0) 
    { 
     description = attributes[0].Description; 
    } 

    return description; 
} 

rằng cách

e.Value = Enum.GetName(typeof(States), e.Value).Description; 

Tất cả những gì bạn phải làm là kiểm tra xem bạn đã xác định tất cả các giá trị enum có thể và rằng yo bạn đang hoạt động trên cột đúng.

Nếu bạn có 1000 giá trị trong cột trạng thái, không có gì có thể giúp bạn tự động hóa điều này trong .Net, nhưng đó là công việc phải được thực hiện một lần. Vì vậy, nó không phải là khó.

+0

Xin lỗi nếu tôi không rõ ràng ... Chỉ có 6 trạng thái khác nhau, ý tôi là khi có hơn 1000 cột trong datatable nó nhận được thực sự chậm ... Ngoài ra, giải pháp bạn cung cấp là những gì tôi hiện đang làm với phương thức getEnumStringValue, nhưng tôi muốn biết nếu có một cách tốt hơn so với các sự kiện định dạng phù thủy cháy cho mỗi cột, ngay cả những người không cần phải tạo ... Tôi sẽ sửa bài của tôi để làm cho mọi thứ rõ ràng hơn –

2

Vì bạn nói DGV này là "chỉ đọc", bạn có thể đọc bảng dữ liệu thành danh sách loại tùy chỉnh thực hiện chuyển đổi tại chỗ.

Bạn có thể thoát khỏi try-catch và phương pháp tùy chỉnh của bạn và chỉ cần viết:

e.Value = ((StatusType)e.Value).ToString(); 

Nếu giá trị không phân tích cú pháp, nó sẽ được hiển thị như giá trị số nguyên của nó. Điều đó sẽ tăng tốc độ lên một chút.

+0

Tôi đã sử dụng Bomm's awnser nhưng với cách của bạn đúc giá trị để thoát khỏi try..catch để tăng tốc độ mọi thứ. Cảm ơn bạn đã anwser của bạn –

+0

Tôi chỉ nhận ra rằng các diễn viên thậm chí không cần thiết. – Tergiver

+0

Rất tiếc, bạn cần dàn diễn viên nếu loại trong bảng dữ liệu là số nguyên. Tôi cần thêm cà phê. – Tergiver

1

Bạn có thể sử dụng sự kiện RowPostPaint của DataGridView. Bạn có thể làm như sau.

private void TestGridView_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e) 
    { 
     if(e.RowIndex == -1) return; 
     TestGridView[YourColumnIndex, e.RowIndex].Value = YourEnumValue; // You can get your enum string value here. 
    } 

Trong phương pháp này, bạn cần kiểm tra giá trị bạn muốn cập nhật nếu không điều này sẽ đưa bạn vào vòng lặp vô hạn để cập nhật hàng. Khi giá trị được cập nhật, bạn nên tránh cập nhật lại giá trị. Giải pháp này chỉ áp dụng nếu đây là ô chỉ đọc.

Tôi khuyên bạn nên đi với giải pháp của BFree, nếu điều đó là không thể thì bạn có thể nghĩ về điều này.

0

Đặt một nơi nào đó trước khi bạn gán DataSource cho lưới điện:

DataTable stypes = new DataTable(); 
stypes.Columns.Add("id", typeof(short)); 
stypes.Columns.Add("name", typeof(string)); 
DataRow stype; 
string[] ntypes = new string[] { "Invalid", "Dev", "Activ", "Old" }; 
for(int i = 0; i < ntypes.Length; ++i) { 
    stype = stypes.NewRow(); 
    stype["id"] = i; 
    stype["name"] = ntypes[i]; 
    stypes.Rows.Add(stype); 
} 
colStatus.DataSource = stypes; 
colStatus.DisplayMember = "name"; 
colStatus.ValueMember = "id"; 
+0

Lưu ý: bạn sẽ phải biến nó thành cột ComboBox – Patrick

1

Bạn có thể sử dụng thuộc tính CellTemplate của cột tương ứng. Trước tiên, hãy tạo lớp cho mẫu ô, ghi đè GetFormattedValue

public class VATGridViewTextBoxCell : DataGridViewTextBoxCell 
{ 
    protected override object GetFormattedValue(object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context) 
    { 
     Price.VATRateEnum r = (Price.VATRateEnum)(int)value; 
     switch (r) 
     { 
      case Price.VATRateEnum.None: return "0%"; 
      case Price.VATRateEnum.Low: return "14%"; 
      case Price.VATRateEnum.Standard: return "20%"; 
      default: 
       throw new NotImplementedException() 
     } 
    } 
} 

rồi gán phiên bản mới cho mẫu ô của cột. Lưu ý rằng thay đổi không có hiệu lực cho đến khi bạn làm mới lưới và đó là lý do tại sao tôi đặt nó vào hàm tạo:

public frmGoods() 
{ 
    InitializeComponent(); 
    this.sellingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
    this.buyingVATDataGridViewTextBoxColumn.CellTemplate = new VATGridViewTextBoxCell(); 
} 
Các vấn đề liên quan