2012-03-02 3 views
3
private void but_Click(object sender, RoutedEventArgs e) 
{ 
    (sender as Button).IsEnabled = false; 
    doSomeThing(); 
    (sender as Button).IsEnabled = true; 
} 

처음 단추를 누르면. 사용할 수 없게됩니다. 그런 다음 doSomeThing()을 시작합니다. 그러나이 버튼을 다시 활성화 한 후에 doSomeThing()but_Click 이벤트가 다시 발생하는 동안 버튼을 다시 누르면됩니다.사용 안 함 단추는 WPF에서 이벤트를 발생시킵니다.

그렇다면 버튼이 비활성화되어있는 동안 이벤트 발생을 방지하는 방법은 무엇입니까?

+0

버튼을 클릭하면 실제로 버튼이 비활성화 된 시각적 모양으로 변경됩니까? 그렇지 않은 경우 귀하의 질문은 [이 질문과 유사 할 것 같습니다] (http://stackoverflow.com/questions/9519295/updatelayout-on-wpf-click/9519860#9519860) – ianschol

+0

예 : 시각적 모양이 사용 중지로 바뀝니다. – HelloWorld

답변

1

코드의 문제는 doSomeThing() 방법 UI 스레드에서 실행된다. 따라서 버튼이 제대로 비활성화되지 않았습니다. doSomeThing() 메서드가 다른 스레드에서 실행되도록 코드를 리팩토링하면 정상적으로 작동합니다. 여기에 BackgroundWorker을 사용하는 간단한 예가 있습니다. 그러나 UI 스레드에서 시간 소모적 인 작업을해서는 안된다는 생각입니다. 리팩토링 된 코드는 다음과 같습니다.

public partial class ButtonEnableTest : Window 
{ 
    private BackgroundWorker worker = new BackgroundWorker(); 

    public ButtonEnableTest() 
    { 
     InitializeComponent(); 
     this.worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
     this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
    } 

    void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (this.btn.IsEnabled == false) 
     { 
      this.btn.IsEnabled = true; 
     } 
    } 

    void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     doSomeThing(); 
    } 

    private void doSomeThing() 
    { 
     int i = 5; 
     while (i > 0) 
     { 
      Thread.Sleep(TimeSpan.FromMilliseconds(2000)); 
      System.Diagnostics.Debug.WriteLine("Woke up " + i); 
      i--; 
     } 
    } 

    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     Button btn = (Button) sender; 
     System.Diagnostics.Debug.WriteLine("at ButtonClick"); 
     if (btn.IsEnabled) 
     { 
      btn.IsEnabled = false; 
      this.worker.RunWorkerAsync(); 
     } 
    } 
} 

아이디어를 공유하기 위해 코딩 변환을 수행하지 않았습니다. WPF 버튼을 "btn"으로 명명했습니다.

0
private void but_Click(object sender, RoutedEventArgs e) 
{ 
    Button but = (sender as Button) 
    if(but.IsEnabled) 
    { 
     but.IsEnabled = false; 
     doSomeThing(); 
     but.IsEnabled = true; 
    } 
} 
+0

버튼이 활성화 된 후에 이벤트가 발생합니다. 그럼, 그렇습니다 .IsEnabled는 항상 true 일 것입니다. – HelloWorld

+0

doSomething() 메소드에서 무엇을하고 있습니까? –

+0

대부분의 시간 Thread.Sleep (50) 및 일부 계산 – HelloWorld

3

  • 제어 (e.g.- 버튼)을 제대로 사용할 수 있습니다 ... 어떤 해명이 순서대로 보인다.
  • 주 스레드가 원래 클릭 이벤트를 처리하는 동안 후속 이벤트는 처리되지 않고 대신 대기합니다.
  • 첫 번째 클릭 이벤트가 완료되자 마자 다음 대기 이벤트가 처리됩니다.
  • 이 시점에서 컨트롤이 이미 활성화되었으므로 대기중인 클릭 이벤트가 이벤트 처리기를 다시 트리거합니다.

가능한 해결책은 여러 가지가 있습니다. @Amit이 올바른 방향이라고 생각합니다. 쓰레드를 사용하는 것이 가장 좋은 방법 일 것입니다. 여기

이 단순화 나를 위해 일한 어떤 버전의 : 왜 컨트롤 '상태의 스레드 안전한 조작을위한 Application.DoEvents(), look here

를 사용하는 것이 좋은 설명은

private void Button1_Click(object sender, EventArgs e) 
{ 
    disableControls(); // e.g.- Button1.Enabled = false; 

    // run "doSomething" in a separate thread 
    new Thread(new ThreadStart(doSomething)).Start(); 
} 

private void doSomething() 
{ 
    // do something... make sure it's thread-safe!! 
    // ... 

    enableControls(); // a thread safe enabling of relevant controls 
} 

, 참조 : How to: Make Thread-Safe Calls to Windows Forms Controls

0

TextChanged 이벤트에서 비슷한 문제가 발생하여 해당 코드로 해결했습니다.

private void TB_box_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    //detach event 
    TB_box1.TextChanged -= TB_box_TextChanged; 
    TB_box2.TextChanged -= TB_box_TextChanged; 

    //change my value 
    TB_box1.Text = "a" 
    TB_box2.Text = "b" 

    //attach event  
    TB_box1.TextChanged += TB_box_TextChanged; 
    TB_box2.TextChanged += TB_box_TextChanged; 

}