2012-01-30 3 views
8

ListView 나는 아이템보기 (예를 들어, 목록보기에서 특정 문자열 강조 표시)를 조정하려는 곳에서 항목을 표시하는 방식을 근본적으로 변경하고 싶지는 않습니다.ListView OwnerDraw의 기본 구현

OwnerDraw을 true로 설정하고 강조 표시 효과를 그리는 방법에 대해 머리를 맞출 수는 있지만 기본 구현을 지연하여 목록보기 항목의 나머지 부분을 그릴 때마다 문제가 발생합니다. 사실은 완전히 잘못되었다는 것을 나타내는 전체적인 그래픽 문제가 남았습니다.

DrawItemDrawSubItem 이벤트의 "기본"처리기가 ​​내 이해를 돕고 내 코드를 더 쉽게 조정할 수있는 곳이 있습니까? 여기에 참고로

이 조각은 내가 현재 뭘하는지 보여주는이 완전히 당신을 도울 것입니다 경우

public MyListView() 
{ 
    this.OwnerDraw = true; 
    this.DoubleBuffered = true; 
    this.DrawColumnHeader += new DrawListViewColumnHeaderEventHandler(MyListView_DrawColumnHeader); 
    this.DrawItem += new DrawListViewItemEventHandler(MyListView_DrawItem); 
    this.DrawSubItem += new DrawListViewSubItemEventHandler(MyListView_DrawSubItem); 
} 

private void MyListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) 
{ 
    // Not interested in changing the way columns are drawn - this works fine 
    e.DrawDefault = true; 
} 

private void MyListView_DrawItem(object sender, DrawListViewItemEventArgs e) 
{ 
    e.DrawBackground(); 
    e.DrawFocusRectangle(); 
} 

private void MyListView_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) 
{ 
    string searchTerm = "Term"; 
    int index = e.SubItem.Text.IndexOf(searchTerm); 
    if (index >= 0) 
    { 
     string sBefore = e.SubItem.Text.Substring(0, index); 

     Size bounds = new Size(e.Bounds.Width, e.Bounds.Height); 
     Size s1 = TextRenderer.MeasureText(e.Graphics, sBefore, this.Font, bounds); 
     Size s2 = TextRenderer.MeasureText(e.Graphics, searchTerm, this.Font, bounds); 

     Rectangle rect = new Rectangle(e.Bounds.X + s1.Width, e.Bounds.Y, s2.Width, e.Bounds.Height); 
     e.Graphics.FillRectangle(new SolidBrush(Color.Yellow), rect); 
    } 

    e.DrawText(); 
} 
+0

난 당신이 잘못 무슨 일이 일어나고 있는지에 대한 자세한 정보를 추가 할 필요가 있다고 생각합니다. 나는 당신의 코드를 테스트했고 그것은 ... 오케이. "Term"이라는 단어를 노란색 상자로 강조 표시했습니다. 어쩌면 드로잉 결과의 이미지를 보여줄 수도 있습니다. – LarsTech

+0

@LarsTech 더 이상 볼 수없는 선택 효과 (위의 샘플에서 볼 수 있음)에서 항목 텍스트를 "이중 렌더링"으로, 항목 위로 마우스를 가져 가면 사라지는 등 광범위한 문제가 발생합니다. 나는 누군가가이 문제들 중 일부 또는 전부를 마술로 해결할 수있을 것이라고 기대하지는 않는다. (미래 사용자를 돕기에는 너무 구체적 일 것이다.) 오히려 모든 것을 가능한 한 가깝게 만드는 예제 구현을보고 싶다. 표준 구현 – Justin

답변

10

지금은 완전한 답을 쓸 시간이 없으므로 대신에 간단한 메모를 적어두고 나중에 다시 보겠습니다. LarsTech 말했듯이

, 소유자가 ListView 제어를 그리기 고통 - 닷넷 ListView 클래스는 기본 Win32 List View Control 래퍼와 "소유자 그릴"할 수있는 기능입니다 NM_CUSTOMDRAW notification code에 의해 제공됩니다. 따라서 "기본 .Net 구현"이 없습니다. 기본값은 기본 Win32 컨트롤을 사용하는 것입니다.

  • LarsTech는 지적은 사실 첫 번째 하위 항목은 상위 항목 자체를 나타내며, 그래서 당신은 모두 렌더링 핸들 경우 :

    더욱 어려운 생활 추가 고려 사항의 숫자가 수 있도록되어 있는지 확인하려면 DrawItemDrawSubItem 첫 번째 셀의 내용을 두 번 그리는 것이 좋습니다.
  • 의 참고 사항에 설명되어있는 기본 목록보기 컨트롤에 DrawItem 이벤트가 발생하여 해당 DrawSubItem 이벤트가 발생하지 않는 버그가 있습니다. 즉, DrawItem 이벤트에 배경을 그리고 텍스트를 그릴 경우 DrawSubItem 이벤트에서 마우스를 가져 가면 항목 텍스트가 사라집니다.
  • 렌더링 중 일부는 기본적으로 이중 버퍼링되지 않는 것처럼 보입니다.
  • ItemState 속성이 항상 올바르지 않은 것으로 나타났습니다. 예를 들어 열의 크기를 조정 한 직후에 나타납니다. 결과적으로 나는 그것에 의존하지 않는 것이 최선이라고 생각했습니다.
  • 텍스트가 여러 줄로 나뉘 지 않는지 확인해야합니다. 그렇지 않으면 셀 맨 아래에 렌더링되는 맨 아래 몇 줄의 픽셀이 표시됩니다.
  • 또한 네이티브 목록보기에서 사용하는 추가 패딩을 고려하여 첫 번째 셀을 렌더링 할 때 특별한 고려 사항이 필요합니다. DrawItem 이벤트가 처음 발생하기 때문에
  • 은, 당신이 (예를 들어, 선택 효과)를 DrawItem 핸들러에 그리는 것도 잘 당신이 (예를 들어, 다른 배경 색상으로 특정 세포를 가진)을 DrawSubItem 핸들러에서하는 일에 의해 오버레이 할 수있다. 모든 처리 소유자 도면에서

모든 상당히 관련 사건입니다 - 나는 그것이 최고에, DrawSubItem 이벤트 내부 그리기 모든을 처리하기 위해도 가장 잘 BufferedGraphics 클래스를 사용하여 자신의 이중 버퍼링을 수행 할 수 발견했다.

또한 ObjectListView의 소스 코드를 매우 편리하게 볼 수 있습니다.

마지막으로,이 모든 기능은 목록보기 (내가 사용하는 유일한 모드)의 세부 모드를 처리하기위한 것입니다. 다른 모드도 작동하게하려면 추가 사항이 있다고 생각하십시오. .

기회가 생기면 필자는 예제 코드를 게시하려고합니다.

3

는 나도 몰라,하지만 난 몇 가지 메모를 추가 할 것입니다 :

을 명심해야 할 점은 DrawSubItem도 첫 번째 항목을 그릴 것이며 이는 아마도 double-rendered의 모습을 얻는 곳일 것입니다. 당신의 DrawSubItem 루틴

private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e) { 
    e.DrawBackground(); 
    if ((e.State & ListViewItemStates.Selected) == ListViewItemStates.Selected) { 
    Rectangle r = new Rectangle(e.Bounds.Left + 4, e.Bounds.Top, TextRenderer.MeasureText(e.Item.Text, e.Item.Font).Width, e.Bounds.Height); 
    e.Graphics.FillRectangle(SystemBrushes.Highlight, r); 
    e.Item.ForeColor = SystemColors.HighlightText; 
    } else { 
    e.Item.ForeColor = SystemColors.WindowText; 
    } 
    e.DrawText(); 
    e.DrawFocusRectangle(); 
} 

첫 번째 열에서 그리기되지 않습니다 있는지 확인하고 난 DrawBackground() 루틴을 추가 :

어떤 것들은 (속도를 고려하지 않음)하려고합니다. 강조 표시 사각형에 일부 클리핑을 추가하여 열 매개 변수 외부로 칠하지 않았습니다.

private void listView1_DrawSubItem(object sender, DrawListViewSubItemEventArgs e) { 
    if (e.ColumnIndex > 0) { 
    e.DrawBackground(); 

    string searchTerm = "Term"; 
    int index = e.SubItem.Text.IndexOf(searchTerm); 

    if (index >= 0) { 
     string sBefore = e.SubItem.Text.Substring(0, index); 

     Size bounds = new Size(e.Bounds.Width, e.Bounds.Height); 
     Size s1 = TextRenderer.MeasureText(e.Graphics, sBefore, this.Font, bounds); 
     Size s2 = TextRenderer.MeasureText(e.Graphics, searchTerm, this.Font, bounds); 

     Rectangle rect = new Rectangle(e.Bounds.X + s1.Width, e.Bounds.Y, s2.Width, e.Bounds.Height); 

     e.Graphics.SetClip(e.Bounds); 
     e.Graphics.FillRectangle(new SolidBrush(Color.Yellow), rect); 
     e.Graphics.ResetClip(); 
    } 

    e.DrawText(); 
    } 
} 

일반적으로 ListView 컨트롤을 그리는 소유자는 상처의 세계에서 환영 받고 있습니다. 당신은 더 이상 비주얼 스타일로 그리지 않습니다, 당신도 스스로해야 할 것입니다. 응.

2

항목 선택 백 색이 변경되었습니다. 창에서는 기본적으로 파란색으로 표시됩니다. 이 코드는 어떤 색깔에서 유를 위해 도움이 될 것입니다

private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e) 
    { 
     e.DrawBackground(); 
     if (e.Item.Selected) 
     { 
      e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(250, 194, 87)), e.Bounds); 
     } 
     e.Graphics.DrawString(e.Item.Text, new Font("Arial", 10), new SolidBrush(Color.Black), e.Bounds); 

    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     for (int ix = 0; ix < listView1.Items.Count; ++ix) 
     { 
      var item = listView1.Items[ix]; 
      item.BackColor = (ix % 2 == 0) ? Color.Gray : Color.LightGray; 

     } 

    } 

    private void listView1_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e) 
    { 
     e.DrawDefault = true; 
    } 

    } 
} 
0
private void listView1_DrawItem(object sender, DrawListViewItemEventArgs e) 
    { 
     e.DrawBackground(); 
     if (e.Item.Selected) 
     { 
      e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(250, 194, 87)), e.Bounds); 
     } 
     e.Graphics.DrawString(e.Item.Text, new Font("Arial", 10), new SolidBrush(Color.Black), e.Bounds); 

    } 
관련 문제