단일 ListViewItem의 텍스트를 업데이트할 때 ListView에서 깜박임을 방지하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/87795

  •  01-07-2019
  •  | 
  •  

문제

내가 원하는 것은 깜박임을 보지 않고 ListViewItem의 텍스트를 업데이트하는 것입니다.

이것은 업데이트를 위한 코드입니다(여러 번 호출됨).

listView.BeginUpdate();
listViewItem.SubItems[0].Text = state.ToString();    // update the state
listViewItem.SubItems[1].Text = progress.ToString(); // update the progress
listView.EndUpdate();

구성요소의 재정의와 관련된 몇 가지 솔루션을 보았습니다. WndProc():

protected override void WndProc(ref Message m)
{
    if (m.Msg == (int)WM.WM_ERASEBKGND)
    {
        m.Msg = (int)IntPtr.Zero;
    }
    base.WndProc(ref m);
}

문제가 해결됐다고 하는데 제 경우에는 그렇지 않았어요.나는 모든 항목에 아이콘을 사용하고 있기 때문이라고 생각합니다.

도움이 되었습니까?

해결책 2

이 질문을 끝내기 위해 양식에 있는 각 ListView 또는 다른 ListView 파생 컨트롤에 대해 양식을 로드할 때 호출해야 하는 도우미 클래스가 있습니다.솔루션을 제공한 "Brian Gillespie"에게 감사드립니다.

public enum ListViewExtendedStyles
{
    /// <summary>
    /// LVS_EX_GRIDLINES
    /// </summary>
    GridLines = 0x00000001,
    /// <summary>
    /// LVS_EX_SUBITEMIMAGES
    /// </summary>
    SubItemImages = 0x00000002,
    /// <summary>
    /// LVS_EX_CHECKBOXES
    /// </summary>
    CheckBoxes = 0x00000004,
    /// <summary>
    /// LVS_EX_TRACKSELECT
    /// </summary>
    TrackSelect = 0x00000008,
    /// <summary>
    /// LVS_EX_HEADERDRAGDROP
    /// </summary>
    HeaderDragDrop = 0x00000010,
    /// <summary>
    /// LVS_EX_FULLROWSELECT
    /// </summary>
    FullRowSelect = 0x00000020,
    /// <summary>
    /// LVS_EX_ONECLICKACTIVATE
    /// </summary>
    OneClickActivate = 0x00000040,
    /// <summary>
    /// LVS_EX_TWOCLICKACTIVATE
    /// </summary>
    TwoClickActivate = 0x00000080,
    /// <summary>
    /// LVS_EX_FLATSB
    /// </summary>
    FlatsB = 0x00000100,
    /// <summary>
    /// LVS_EX_REGIONAL
    /// </summary>
    Regional = 0x00000200,
    /// <summary>
    /// LVS_EX_INFOTIP
    /// </summary>
    InfoTip = 0x00000400,
    /// <summary>
    /// LVS_EX_UNDERLINEHOT
    /// </summary>
    UnderlineHot = 0x00000800,
    /// <summary>
    /// LVS_EX_UNDERLINECOLD
    /// </summary>
    UnderlineCold = 0x00001000,
    /// <summary>
    /// LVS_EX_MULTIWORKAREAS
    /// </summary>
    MultilWorkAreas = 0x00002000,
    /// <summary>
    /// LVS_EX_LABELTIP
    /// </summary>
    LabelTip = 0x00004000,
    /// <summary>
    /// LVS_EX_BORDERSELECT
    /// </summary>
    BorderSelect = 0x00008000,
    /// <summary>
    /// LVS_EX_DOUBLEBUFFER
    /// </summary>
    DoubleBuffer = 0x00010000,
    /// <summary>
    /// LVS_EX_HIDELABELS
    /// </summary>
    HideLabels = 0x00020000,
    /// <summary>
    /// LVS_EX_SINGLEROW
    /// </summary>
    SingleRow = 0x00040000,
    /// <summary>
    /// LVS_EX_SNAPTOGRID
    /// </summary>
    SnapToGrid = 0x00080000,
    /// <summary>
    /// LVS_EX_SIMPLESELECT
    /// </summary>
    SimpleSelect = 0x00100000
}

public enum ListViewMessages
{
    First = 0x1000,
    SetExtendedStyle = (First + 54),
    GetExtendedStyle = (First + 55),
}

/// <summary>
/// Contains helper methods to change extended styles on ListView, including enabling double buffering.
/// Based on Giovanni Montrone's article on <see cref="http://www.codeproject.com/KB/list/listviewxp.aspx"/>
/// </summary>
public class ListViewHelper
{
    private ListViewHelper()
    {
    }

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    private static extern int SendMessage(IntPtr handle, int messg, int wparam, int lparam);

    public static void SetExtendedStyle(Control control, ListViewExtendedStyles exStyle)
    {
        ListViewExtendedStyles styles;
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        styles |= exStyle;
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }

    public static void EnableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // enable double buffer and border select
        styles |= ListViewExtendedStyles.DoubleBuffer | ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
    public static void DisableDoubleBuffer(Control control)
    {
        ListViewExtendedStyles styles;
        // read current style
        styles = (ListViewExtendedStyles)SendMessage(control.Handle, (int)ListViewMessages.GetExtendedStyle, 0, 0);
        // disable double buffer and border select
        styles -= styles & ListViewExtendedStyles.DoubleBuffer;
        styles -= styles & ListViewExtendedStyles.BorderSelect;
        // write new style
        SendMessage(control.Handle, (int)ListViewMessages.SetExtendedStyle, 0, (int)styles);
    }
}

다른 팁

허용되는 답변은 작동하지만 꽤 길며 이중 버퍼링을 활성화하기 위해 다른 답변에서 언급한 것처럼 컨트롤에서 파생되는 것도 약간 과도합니다.그러나 다행스럽게도 우리는 반성할 수 있고 원할 경우 내부 메서드를 호출할 수도 있습니다(그러나 무엇을 해야 하는지 확인하십시오!).

이 접근 방식을 확장 메서드로 캡슐화하면 매우 짧은 클래스가 생성됩니다.

public static class ControlExtensions
{
    public static void DoubleBuffering(this Control control, bool enable)
    {
        var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
        method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
    }
}

코드 내에서 쉽게 호출할 수 있습니다.

InitializeComponent();

myListView.DoubleBuffering(true); //after the InitializeComponent();

그리고 모든 깜박임이 사라졌습니다.

업데이트

나는 우연히 발견했다 이 질문 그리고 이 사실 때문에 확장 방법은 (아마도) 다음과 같은 것이 더 나을 것입니다:

public static void DoubleBuffered(this Control control, bool enable)
{
    var doubleBufferPropertyInfo = control.GetType().GetProperty("DoubleBuffered", BindingFlags.Instance | BindingFlags.NonPublic);
    doubleBufferPropertyInfo.SetValue(control, enable, null);
}

CommonControls 6(XP 이상)의 ListView는 이중 버퍼링을 지원합니다.다행히 .NET은 시스템에 최신 CommonControls를 래핑합니다.이중 버퍼링을 활성화하려면 적절한 Windows 메시지를 ListView 컨트롤에 보냅니다.

자세한 내용은 다음과 같습니다.http://www.codeproject.com/KB/list/listviewxp.aspx

.NET Winforms 2.0에는 DoubleBuffered라는 보호 속성이 있습니다.

ListView에서 상속하면 이 보호 속성을 true로 설정할 수 있습니다.이렇게 하면 SendMessage를 호출할 필요 없이 이중 버퍼링이 활성화됩니다.

DoubleBuffered 속성을 설정하는 것은 다음 스타일을 설정하는 것과 같습니다.

listview.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=94096

이 질문이 꽤 오래되었다는 것을 알고 있지만 이것이 Google의 첫 번째 검색 결과 중 하나이기 때문에 해결 방법을 공유하고 싶었습니다.

깜박임을 100% 제거할 수 있는 유일한 방법은 Oliver(이중 버퍼링이 포함된 확장 클래스)의 답변을 결합하고 BeignUpdate() 그리고 EndUpdate() 행동 양식.

그 중 어느 것도 깜박임을 해결할 수 없습니다.물론 저는 매우 복잡한 목록을 사용하므로 목록에 추가하고 거의 매 초마다 업데이트해야 합니다.

이것이 도움이 될 것입니다:

class DoubleBufferedListView : System.Windows.Forms.ListView
{
    public DoubleBufferedListView()
        :base()
    {
        this.DoubleBuffered = true;
    }
}

간단한 해결책은 다음과 같습니다.

yourlistview.BeginUpdate()

//목록에서 항목 추가 및 제거 업데이트를 수행합니다.

yourlistview.EndUpdate()

텍스트만 업데이트하려는 경우 전체 ListViewItem을 업데이트하는 대신 변경된 하위 항목의 텍스트를 직접 설정하면 됩니다(업데이트 수행 방법을 언급하지 않았습니다).

표시하는 재정의는 단순히 OnPaintBackground를 재정의하는 것과 동일합니다. 이는 해당 작업을 수행하는 "보다 정확한" 관리 방법이며 단일 항목에는 도움이 되지 않습니다.

여전히 문제가 있는 경우 실제로 시도한 작업에 대한 설명이 필요합니다.

이것은 어둠 속에서의 장면이지만 컨트롤을 이중 버퍼링해 볼 수 있습니다.

SetStyle(
  ControlStyles.AllPaintingInWmPaint |
  ControlStyles.UserPaint |
  ControlStyles.DoubleBuffer, true)

목록 보기 항목을 설정하기 전에 ListView에서 BeginUpdate() 메서드를 호출한 다음 모든 항목이 추가된 후에만 EndUpdate()를 호출합니다.

그러면 깜박임이 중지됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top