2013-07-09 9 views
5

배경 해고 누가 결정 : 내 윈폼 양식에서이벤트

을, 나는 검사 ListView를checkBoxAll라는 "마스터"체크 박스가 있습니다. 다음과 같이 마스터의 동작은 다음과 같습니다 마스터가 선택 또는 선택되어

  • 경우, 모든 ListViewItems에 따라 변경해야합니다.

  • 사용자가 ListViewItem의 선택을 취소하면 그에 따라 마스터를 변경해야합니다.

  • 사용자가 ListViewItem을 검사하고 다른 모든 ListViewItem도 검사하면 그에 따라 마스터를 변경해야합니다. 내가이 동작을 모방하려면 다음 코드를 작성했습니다

:

private bool byProgram = false; //Flag to determine the caller of the code. True for program, false for user. 

private void checkBoxAll_CheckedChanged(object sender, EventArgs e) 
{ 
    //Check if the user raised this event. 
    if (!byProgram) 
    { 
     //Event was raised by user! 

     //If checkBoxAll is checked, all listviewitems must be checked too and vice versa. 

     //Check if there are any items to (un)check. 
     if (myListView.Items.Count > 0) 
     { 
      byProgram = true; //Raise flag. 

      //(Un)check every item. 
      foreach (ListViewItem lvi in myListView.Items) 
      { 
       lvi.Checked = checkBoxAll.Checked; 
      } 

      byProgram = false; //Lower flag. 
     } 
    } 
} 

private void myListView_ItemChecked(object sender, ItemCheckedEventArgs e) 
{ 
    //Get the appropiate ListView that raised this event 
    var listView = sender as ListView; 

    //Check if the user raised this event. 
    if (!byProgram) 
    { 
     //Event was raised by user! 

     //If all items are checked, set checkBoxAll checked, else: uncheck him! 

     bool allChecked = true; //This boolean will be used to set the value of checkBoxAll 

     //This event was raised by an ListViewItem so we don't have to check if any exist. 
     //Check all items untill one is not checked. 
     foreach (ListViewItem lvi in listView.Items) 
     { 
      allChecked = lvi.Checked; 
      if (!allChecked) break; 
     } 

     byProgram = true; //Raise flag. 

     //Set the checkBoxAll according to the value determined for allChecked. 
     checkBoxAll.Checked = allChecked; 

     byProgram = false; //Lower flag. 
    } 
} 

이 예에서는, 나는 확실히 이벤트가 사용자에 의해 여부 기인했다을 만들기 위해 플래그 (byProgram)를 사용 무한 루프 (하나의 이벤트가 다른 이벤트를 발사하여 첫 번째 이벤트를 다시 실행할 수있는 등)를 방지합니다. IMHO, 이것은 해킹 된 솔루션입니다. 나는 주위를 검색했지만 사용자 컨트롤 이벤트가 사용자의 도움으로 직접 실행되었는지 확인하기 위해 MSDN 문서화 된 메서드를 찾을 수 없습니다. 이상하게 여겨지는 (다시, IMHO).

FormClosingEventArgs에는 사용자가 양식을 닫는 지 여부를 결정하는 데 사용할 수있는 필드가 있습니다.

이벤트가 있다면 결정하기 위해 (내 예) 이외의 다른 방법이 :하지만 내가 아는 한, 그 기능이 종류를 제공하는 유일한 EventArg ... 요약 그래서

입니다 사용자가 직접 해고 했나요?

참고 : 나는 이벤트의 발신자가 아닙니다. 내가 someCheckBox.Checked = true를 코딩하면 상관 없습니다. 또는 someCheckBox를 수동으로 설정하면 이벤트 발신자는 항상 someCheckBox가됩니다. 나는 그것이 사용자 (클릭) 또는 프로그램 (.Checked = true)에 의한 것인지 여부를 판별하는 것이 가능한지 알아야합니다.

Aaand 또한 :이 질문을 작성하는 데 걸린 시간의 30 %는 질문과 제목을 올바르게 공식화하는 것이 었습니다. 그래도 100 % 확실한 지 확실하지 않으므로 더 잘 할 수 있다고 생각한다면 편집하십시오.

+0

그냥 자연스럽게 추측 할 수 있지만 실제로 EventArgs에는 뭔가 있어야합니다. 런타임에 검사 (디버깅) 했습니까? –

+0

클릭 이벤트에서이 호출이 코드가 아닌 클릭으로부터 온 것임을 알리는 플래그를 설정합니까? – MEYWD

+0

'발신자'를 사용 하시겠습니까? – DGibbs

답변

2

이 내가 꽤 많이 건너 뭔가하고 제가 프로그램 대 사용자 상호 작용 사이에 분할되지 수행하려고하는 경향이있다 : 당신은 제거하고 이전에 이벤트 처리기를 추가하거나, 이후에 각각 당신의 컨트롤을 바꿀 수 interaction -보다 일반적인 코드를 사용합니다. 즉, UI가 업데이트되고 처리 할 이벤트가 필요하지 않습니다. 일반적으로 이것을 BeginUpdate/EndUpdate 방법을 통해 패키지합니다.

private int updates = 0; 

public bool Updating { get { return updates > 0; } } 

public void BeginUpdate() 
{ 
    updates++; 
} 

public void EndUpdate() 
{ 
    updates--; 
} 

public void IndividualCheckBoxChanged(...) 
{ 
    if (!Updating) 
    { 
     // run code 
    } 
} 

public void CheckAllChanged(...) 
{ 
    BeginUpdate(); 
    try 
    { 
     // run code 
    } 
    finally 
    { 
     EndUpdate(); 
    } 
} 
+1

+1, 여전히 깃발이지만 다음에 깃발을 올릴 필요가있을 때이 건축물을 사용할 것입니다. – Jordy

+0

@ Jordy * 다른 * 깃발이 아니라 구조와 의미를 더 추가하여 기존 깃발을 개선 한 것입니다. 'BeginUpdate' /'EndUpdate' 패턴은 다양한 플랫폼 (.NET 포함) 전반에 걸쳐 이런 종류의 문제에 대해 잘 사용되거나 채택 된 접근 방식입니다. 아이디어는 이벤트가 연결되었는지 여부에 관계없이 "상태"에 반응하고 있다는 것이므로 훨씬 더 읽기 쉬운 코드가됩니다. – James

+0

나는 ... 아마 "아직 깃발"이라고 묘사해서는 안된다. 하지만 웬일인지 내 의견을 편집 할 수 없다. 너무 오래되었거나 뭔가가있다. \ – Jordy

4

변경된 이벤트를 사용하는 대신 클릭 된 이벤트를 사용하여 변경 사항을 관련 컨트롤로 케스케이드 할 수 있습니다. 이것은 사용자 클릭에 대한 응답 일 뿐이며 값은 프로그래밍 방식으로 변경되지 않습니다.

+0

+1 여분의 플래그를 포함하지 않는 솔루션을 제공합니다. 하지만 재산이 실제로 변경된 사실을 알고 있습니까? 그건 옛날 값을 저장하는 것과 관련이 있을까요? – Jordy

+1

모두 선택 상자에서 클릭 이벤트가 발생하면 모든 체크 박스의 값을 설정할 수 있습니다. 옵션 항목 중 하나에서 클릭 이벤트가 발생하면 옵션의 상태에 따라 모두 선택 확인란 만 업데이트합니다. –

+0

네가 맞아! 나는 걱정하지 않으며 가치가 없거나 변하지 않았다. 나는 현재 가지고있는 가치를 볼 수 있습니다. – Jordy

5

아니요, 변경 사항이 GUI에서 왔는지 또는 프로그램에서 수행되었는지 확인할 수있는 실용적인 방법이 없습니다. 실제로는 호출 스택을 분석 할 수 있지만 속도가 느리고 오류가 발생하기 때문에 권장되지 않습니다.

현재로서는 byProgram을 설정하는 대신 할 수있는 것이 하나 있습니다.

checkBoxAll.CheckedChanged -= checkBoxAll_CheckedChanged; 
// do something 
checkBoxAll.CheckedChanged += checkBoxAll_CheckedChanged; 
+0

이것은 내가 정기적으로하는 일입니다. – dotNET

+0

+1 여분의 이벤트 나 플래그를 포함하지 않는 솔루션을 제공하는 경우 +1! – Jordy

+1

나는 이런 식으로 이벤트 처리기를 분리/다시 부착하는 것은 좋은 생각이 아니라고 주장합니다. * 약간의 오버 헤드 외에도 20 개의 이벤트 핸들러가 있다면 어떨까요? 다시 연결하거나 분리하는 것을 잊어 버릴 확률이 항상 있기 때문에 이벤트가 연결되는지 여부가 아닌 "상태"에 반응하기 때문에 차단 코드가 더 좋습니다. – James