Databound numericupdown 'скрывает' исключение, выброшенное в связанное свойство

У меня возникла проблема, когда исключение, создаваемое из средства доступа к набору свойств, не перехватывается моим глобальным обработчиком исключений.

У меня была проблема в более крупном приложении, и после долгих скрежетов зубов, устраняющих проблему, я попытался и преуспел в воспроизведении проблемы в более простом проекте.

Ниже приведен код и поведение. Может кто-нибудь объяснить это поведение, пожалуйста, и как мне правильно кодировать для достижения желаемого результата, а именно для того, чтобы исключение было перехвачено глобальным обработчиком событий.

//Program.cs - Wire up global exception handling
static class Program
{
[STAThread]
static void Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);

    Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);
    Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

    Application.Run(new Form1());
}

static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
{
    MessageBox.Show("Exception occured : " + e.Exception.Message);
}

*

//In main form create instance of class containing bound property and setup databinding
//to numericUpDown control
private void Form1_Load(object sender, EventArgs e)
{
    _car = new Car();
    _car.NumberOfWheels = 4;
    numericUpDown1.DataBindings.Add(new Binding("Value", _car, "NumberOfWheels", true, DataSourceUpdateMode.OnPropertyChanged));
}

*

public int NumberOfWheels
{
    get { return _numberOfWheels; }
    set
    {
        if (value < 4)
            //Throw some exception
            throw new ArgumentNullException("Argument null exception trigger in Number Of Wheels property");

         _numberOfWheels = value;
    }

}

Если я установлю точку останова в строке 'throw new ArgumentNullException', программа обязательно остановится в этот момент, когда я изменю значение элемента управления numericUpDown (которое привязано к свойству NumberOfWheels). Однако это единственный способ определить, сгенерировано ли исключение. Через пользовательский интерфейс не отображается сообщение о том, что создается исключение, т. е. оно не перехватывается глобальным обработчиком исключений.

В отличие от этого, если я изменяю значение свойства с помощью нажатия кнопки, тогда исключение выдается И перехватывается моим обработчиком с отображением окна сообщения.

Что мне не хватает?


person Community    schedule 03.03.2009    source источник


Ответы (2)


Привязка будет «проглатывать» или «скрывать» исключение. Это, по-видимому, для большей отказоустойчивости.

Вам необходимо прослушать событие BindingComplete и проверить BindingCompleteState в свойстве BindingCompleteEventArgs BindingCompleteState. Если это значение — BindingCompleteState.Exception, свойство BindingCompleteEventArgs Exception будет содержать созданное исключение.

    public Form1()
    {
        InitializeComponent();

        Binding binding = new Binding("Value", _car, "NumWheels", true, DataSourceUpdateMode.OnPropertyChanged);
        numericUpDown1.DataBindings.Add(binding);
        binding.BindingComplete += new BindingCompleteEventHandler(binding_BindingComplete);

    }

    void binding_BindingComplete(object sender, BindingCompleteEventArgs e)
    {
        if (e.BindingCompleteState == BindingCompleteState.Exception)
        {
            throw e.Exception;
        }
    }
person Mufaka    schedule 03.03.2009

Спасибо, Муфака.

Это было очень полезно и позволило мне расширить свои знания о привязке данных. Однако исключение по-прежнему не перехватывается глобальным обработчиком исключений. Код прерывается на последнем '}' в binding_BindingComplete, и отображается сообщение "ArgumentNullException не было обработано пользовательским кодом".

Единственный способ заставить его работать, как вы описываете, - это установить

binding.FormattingEnabled = false;

но это, кажется, имеет свои собственные проблемы.

Я думаю, что сейчас я воспользуюсь вашим подходом, но вместо того, чтобы снова создавать исключение, я покажу окно сообщения и восстановлю исходное значение.

private void binding_BindingComplete(object sender, BindingCompleteEventArgs e)
{
   if (e.BindingCompleteState == BindingCompleteState.Exception)
   {
       MessageBox.Show(e.Exception.Message);
       e.Binding.ReadValue(); //resets value to actual value of data source instead of leaving it as changed value of control
   }
}

Вероятно, я смогу использовать этот обработчик для всех элементов управления с привязкой к данным.

person SleepyBoBos    schedule 04.03.2009