为什么委托订阅者在事件通过后被调用?

时间:2011-04-26 21:03:59

标签: .net wpf events delegates

我不知道怎么问这个,但是这里有。我有一个WPF窗口,其中有一个委托响应TextBox的TextChanged事件。当我将数据加载到窗口中,然后将我的控制器类订阅到该事件时,将调用委托处理程序方法。

顺序就是这个。 1.创建窗口 2.加载该窗口的数据。 3.使用TextDidChange方法订阅窗口的TextChanged事件。

在这种情况下,即使在步骤2中发生“事件”,我的TextDidChange方法也会被调用。这是预期的行为吗?如果没有,可能会发生什么?

编辑: 这是相关的代码。我没有从UserControl发布事件处理,因为它是样板(如果委托!= null,则调用委托)。

来自Controller构造函数:

public ServiceRequestVM(Boolean isDataSourceProd, codExistServiceRequestSearchType requestIdOrMapNo, String aMapNumber, Decimal aRequestId) {
        //create the schema and load any necessary data
        _sroc = new ServiceRequestOracleController();
        _sroc.IsProd = isDataSourceProd;
        _isProd = isDataSourceProd;
        _isNewRequest = false;
        _searchType = requestIdOrMapNo;
        createSchema();

        if (requestIdOrMapNo == codExistServiceRequestSearchType.MapNumber) {
            loadMatchingRequest(aMapNumber);
        } else {
            loadMatchingRequest(aRequestId);
        }
        Decimal _reqId = (Decimal)_serviceRequestTable.Rows[0]["REQUESTID"];
        loadNotesForRequest(_reqId);
        loadTagsForRequest(_reqId);
        Decimal _custId = (Decimal)_serviceRequestTable.Rows[0]["CUSTOMERID"];
        getNameForCustomerAndSetCustomerIdForRequest(_custId);

        //configure the UI
        configureUI();
        customerListBoxVisibility = Visibility.Hidden;
        tagListBoxVisibility = Visibility.Hidden;

        //create the view (a UserControl)
        _serviceRequestView = new ServiceRequestView();
        _serviceRequestView.DataContext = this;

        //load customers and tags
        loadCustomers();
        loadTags();

        _shouldListBoxesBeSeen = false;

        //subscribe to delegates
        subscribeToRequestDelegates();
    }

subscribeToRequestDelegates方法

    private void subscribeToRequestDelegates() {
        _serviceRequestView.addNoteButtonWasClicked += new ServiceRequestView.AddNoteButtonWasClickedHandler(addNote);
        _serviceRequestView.addTagButtonWasClicked += new ServiceRequestView.AddTagButtonWasClickedHandler(addTag);
        _serviceRequestView.locateButtonWasClicked += new ServiceRequestView.LocateButtonWasClickedHandler(locateMap);
        _serviceRequestView.openButtonWasClicked += new ServiceRequestView.OpenButtonWasClickedHandler(openMap);
        _serviceRequestView.saveButtonWasClicked += new ServiceRequestView.SaveButtonWasClickedHandler(saveRequest);
        _serviceRequestView.noteWasDoubleClicked += new ServiceRequestView.NoteWasDoubleClickedHandler(openSelectedNote);
        _serviceRequestView.dateCompletedLostFocus += new ServiceRequestView.DateCompletedLostFocusHandler(dateCompletedDidChange);
        _serviceRequestView.titleLostFocus += new ServiceRequestView.TitleLostFocusHandler(titleDidChange);
        _serviceRequestView.customerTextChanged += new ServiceRequestView.CustomerTextChangedHandler(customerTextDidChange);
        _serviceRequestView.selectedCustomerChanged += new ServiceRequestView.SelectedCustomerChangedHandler(selectedCustomerDidChange);
        _serviceRequestView.tagTextChanged += new ServiceRequestView.TagTextChangedHandler(tagTextDidChange);
        _serviceRequestView.selectedTagChanged += new ServiceRequestView.SelectedTagChangedHandler(selectedTagDidChange);
        _serviceRequestView.tagTextLostFocus += new ServiceRequestView.TagTextLostFocusHandler(tagTextLostFocus);
        _serviceRequestView.customerTextLostFocus += new ServiceRequestView.CustomerTextLostFocusHandler(customerTextLostFocus);
        _serviceRequestTable.ColumnChanged += new DataColumnChangeEventHandler(serviceRequestTableColumnValueDidChange);
    }

1 个答案:

答案 0 :(得分:0)

我无法确定WPF正在做什么,但在Windows的引擎盖下,控件的文本通常通过向窗口发送消息来更新。这是放在应用程序的消息队列中,只有在UI线程处理消息时才会处理 - 所以如果你的UI线程正在处理控件,那么你必须完成初始化并将控制返回到主消息处理循环(或在控件接收和处理消息之前调用DoEvents())。即它以异步方式发生。 (您也可以向控件“发布”一条消息,它等待控件在返回代码之前处理消息,但是WPF可能/可能没有以这种方式调用它)

最简单的解决方法是将“guard”变量放入您的类中以避免对“内部”调用做出反应,并让事件处理程序在设置时忽略这些事件:

bool suppressTextChanged;

void Initialize()
{
    suppressTextChanged = true;
    control.SetText("abcd");
    suppressTextChanged = false;
    ...
}

void Control_TextChanged(object sender, EventArgs e)
{
    if (suppressTextChanged) return;
    ...
}

这是一个丑陋但有效的解决方案。令人遗憾的是,Windows从未提供区分用户驱动事件的方式(例如,用户在控件中编辑它的文本更改)和内部事件(由程序在内部更新控件驱动) - 尽管对于某些事件,您可以使用“发件人”确定事件的来源,以便弄清楚它是如何被触发的。