Почему делегат подписчика вызывается после того, как событие прошло? - PullRequest
0 голосов
/ 27 апреля 2011

Я не уверен, как спросить это, но здесь идет. У меня есть окно WPF с делегатом, который отвечает на событие TextChanged TextBox. Когда я загружаю данные в окно, а затем подписываю свой класс контроллера на это событие, вызывается метод обработчика делегата.

Последовательность такая. 1. Создать окно 2. Загрузите данные для этого окна. 3. Подпишитесь на событие TextChanged для окна с помощью метода TextDidChange.

В этом случае мой метод TextDidChange вызывается, даже если «событие» произошло на шаге 2. Это ожидаемое поведение? Если нет, то что может происходить?

EDIT: Вот соответствующий код. Я не опубликовал обработку событий из UserControl, так как это шаблон (если делегат! = Null, вызовите делегат).

Из конструктора контроллера:

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 голосов
/ 27 апреля 2011

Я не могу точно сказать вам, что делает WPF, но под капотом в окнах текст элемента управления обычно обновляется, посылая окну сообщение.Это помещается в очередь сообщений приложения и обрабатывается только тогда, когда поток пользовательского интерфейса приступает к обработке сообщений - поэтому, если управление обрабатывается вашим потоком пользовательского интерфейса, тогда вы должны завершить инициализацию и вернуть управление в основной цикл обработки сообщений.(или вызовите DoEvents ()) до того, как элемент управления получит и обработает сообщение.то есть это происходит асинхронно.(Вы также можете «опубликовать» сообщение для элемента управления, который ожидает, пока элемент управления обработает сообщение, прежде чем оно вернется в ваш код, но возможно / вероятно, что WPF не вызывает его таким образом)

Самое простое решение - поместить переменную guard в ваш класс, чтобы избежать реакции на «внутренние» вызовы, и обработчик событий игнорирует события, когда они установлены:

bool suppressTextChanged;

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

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

Это уродливо, но эффективнорешение.Жаль, что окна никогда не обеспечивали способ дифференциации управляемых пользователем событий (например, текста, измененного пользователем, который редактировал его в элементе управления) и внутренних событий (управляемых вашей программой, обновляющих элемент управления внутри) - хотя для некоторых событий вы можете использовать«отправитель» для определения источника события, чтобы определить, как оно было инициировано.

...