C# 2个相互呼叫的事件
我想知道这个问题有一段时间了,但没有真正想出一个解决办法。我有两个不同的事件处理程序递归地互相调用。一旦触发事件A,它就会触发事件B,而事件B会再次触发事件A,以此类推 基本上,我希望能够在RichTextBox中选择文本,并在组合框中显示相应的字体大小。当我从组合框中选择不同的字体大小时,我希望它的值应用于所选文本 这两项活动是: 1) RichTextBox中文本的选择更改事件:C# 2个相互呼叫的事件,c#,event-handling,C#,Event Handling,我想知道这个问题有一段时间了,但没有真正想出一个解决办法。我有两个不同的事件处理程序递归地互相调用。一旦触发事件A,它就会触发事件B,而事件B会再次触发事件A,以此类推 基本上,我希望能够在RichTextBox中选择文本,并在组合框中显示相应的字体大小。当我从组合框中选择不同的字体大小时,我希望它的值应用于所选文本 这两项活动是: 1) RichTextBox中文本的选择更改事件: private void MyRTB_SelectionChanged(object sender, Route
private void MyRTB_SelectionChanged(object sender, RoutedEventArgs e)
{
//Get the font size of selected text and select the concurrent size from the ComboBox.
}
2) 组合框的选定索引已更改事件:
private void CmbFont_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//Apply the chosen font size to the currently selected text of the RichTextBox.
}
最好的解决方案是什么,以确保他们每个人都只“做自己的事”,并且在这样做时不触发其他事件?重构您的代码,以便A调用
DoSomethingA()
,B调用DoSomethingB()
。这样,如果你想让A实现B的功能,你可以只调用DoSomethingB()
,而不进行任何递归调用。重构你的代码,使A调用DoSomethingA()
,B调用DoSomethingB()
。这样,如果您想让A执行B的功能,您可以只调用DoSomethingB()
,而不进行任何递归调用。只需在调用B之前使用bool(可能称为dontFireA)并将其设置在A中只需在调用B之前使用bool(可能称为dontFireA)并将其设置在A中通知属性(用于启用从WPF到非WPF属性的绑定)使用以下技术:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
if(value!=myField)条件防止无限递归(stackoverflowexception)。
在某些情况下(例如浮点数和不准确的值传输),使用if(Math.Abs(value-myField)>someConstant)来中断递归
你能用类似的方法解决你的问题吗
如果两个事件都在同一个对象上,或者所有者彼此有引用,则还可以在每个事件上存储一个标志,例如
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
通知属性(用于启用从WPF到非WPF属性的绑定)使用以下技术:
public object MyProperty
{
get
{
return myField;
}
set
{
if (value != myField)
{
myField = value;
NotifyProperyChanged("MyProperty"); // raise event
}
}
}
if(value!=myField)条件防止无限递归(stackoverflowexception)。
在某些情况下(例如浮点数和不准确的值传输),使用if(Math.Abs(value-myField)>someConstant)来中断递归
你能用类似的方法解决你的问题吗
如果两个事件都在同一个对象上,或者所有者彼此有引用,则还可以在每个事件上存储一个标志,例如
private void OnEvent()
{
DoSomething();
}
private void DoSomething()
{
this.IsBusy = true;
// do work
// raise event
if (!other.IsBusy)
RaiseEvent();
}
有时,更改代码中控件的属性会无意中触发事件。例如,更改列表框或组合框的数据源将触发
SelectedIndexChanged
事件。使用标志处理此情况
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
在事件处理程序中,执行此操作
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
有时,更改代码中控件的属性会无意中触发事件。例如,更改列表框或组合框的数据源将触发
SelectedIndexChanged
事件。使用标志处理此情况
private bool _loading;
...
_loading = true;
// Fill the ComboBox or ListView here
_loading = false;
在事件处理程序中,执行此操作
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (_loading) return;
...
}
我将做出有根据的猜测,您自己不会引发事件A或事件B;假设事件A是TextBox1.TextChanged事件,事件B是TextBox2.TextChanged事件,它们具有如下处理程序:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
在本例中,每个处理程序都将通过更改文本来引发另一个textbox的TextChanged事件,从而导致无限递归
如果希望两者都运行一次且仅运行一次,则可以做的第一件事是标记它们已在运行(更改另一个textbox的文本会导致该textbox的事件处理程序在同一调用堆栈中运行:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
现在,它将深入到三个级别:1的处理程序调用2的处理程序,2的处理程序再次调用1的处理程序,该处理程序看到1的处理程序已经在运行,并在执行任何深化递归的操作之前退出。如果从更改TextBox2开始,情况也是如此
您可以做的另一件事是确保您没有尝试将textbox设置为已经存在的相同值。从一个字符串引用更改为另一个字符串引用,即使两个引用都是相同的字符串值,也会触发TextChanged事件。如果递归必须自然继续,但将达到稳定状态,这实际上是第一次要尝试的事情:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}
我将做出有根据的猜测,您自己不会引发事件A或事件B;假设事件A是TextBox1.TextChanged事件,事件B是TextBox2.TextChanged事件,它们具有如下处理程序:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
...
TextBox2.Text = someString;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
...
TextBox1.Text = someOtherString;
}
在本例中,每个处理程序都将通过更改文本来引发另一个textbox的TextChanged事件,从而导致无限递归
如果希望两者都运行一次且仅运行一次,则可以做的第一件事是标记它们已在运行(更改另一个textbox的文本会导致该textbox的事件处理程序在同一调用堆栈中运行:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
if(handler1Running) return; //the second time through we exit immediately
handler1Running = true;
...
TextBox2.Text = "Something"; //the other event handler is invoked immediately
handler1Running = false;
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
if(handler2Running) return; //the second time through we exit immediately
handler2Running = true;
...
TextBox1.Text = "Something Else"; //the other event handler is invoked immediately
handler2Running = false;
}
现在,它将深入到三个级别:1的处理程序调用2的处理程序,2的处理程序再次调用1的处理程序,该处理程序看到1的处理程序已经在运行,并在执行任何深化递归的操作之前退出。如果从更改TextBox2开始,情况也是如此
您可以做的另一件事是确保您没有尝试将textbox设置为已经存在的相同值。从一个字符串引用更改为另一个字符串引用,即使两个引用都是相同的字符串值,也会触发TextChanged事件。如果递归必须自然继续,但将达到稳定状态,这实际上是第一次要尝试的事情:
public void Textbox1_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox2.Text)
TextBox2.Text = builder.ToString();
}
public void Textbox2_TextChanged(object sender, EventArgs e)
{
StringBuilder builder = new StringBuilder();
... //build string
//now, even though the builder's ToString will produce a different reference,
//we're making sure we don't unnecessarily change the text.
if(builder.ToString != TextBox1.Text)
TextBox1.Text = builder.ToString();
}
你能更详细地描述一下你正在解决什么问题吗?我想如果我们有比事件a触发事件B(递归触发事件a)更好的上下文,我们就能给你更好的答案。需要进行一些重新设计。为什么他们互相调用,而不调用任何提供你想要触发的功能的方法?你知道吗