четверг, марта 15, 2007

Der heldenhafte und sinnlose Kampf

VS2005 в очередной раз подтвердила свою репутацию полубезумного средства разработки. А именно.

Следите за руками:

private void Terminate(IAsyncPropertySheet Aps)

{

Aps.Event.WaitOne();

}
используется так:
IAsyncPropertySheet aps = propSheet as IAsyncPropertySheet;



if (m_IsLastSheet m_SingleSheet)

if(aps == null)

DialogResult = DialogResult.OK;

else

{

btnNext.Enabled = false;

btnPrev.Enabled = false;



OneParamDelegate terminate = Terminate;

terminate.BeginInvoke(aps, Callback, null);

}
а Callback выглядит проще некуда
private void Callback(IAsyncResult ar)

{

InnerHide();

DialogResult = DialogResult.OK;

}



void InnerHide()

{

if (InvokeRequired)

{

ParameterlessDelegate del = InnerHide;

Invoke(del);

}

else

Hide();

}
Другими словами, форма не будет закрыта, пока событие интерфейса, реализуемого страницей свойств, не будет установлено в signaled: какой-то полезный код работает на странице и когда отработает, установит событие, по которому форма и закроется. Дёшево и сердито. На всякий случай, чтобы не было недосказанностей, вот событие, используемое для закрытия
public ManualResetEvent Event

{

get {return (Exporter as IAsyncExecution).Event;}

}
при этом Exporter, само собой, инициализируется в конструкторе. Класс, реализующий IAsyncExecution, выглядит так:
public class InternalYYYFactory: Notifier, IExport, IExportInitializer, IAsyncExecution
{

private ManualResetEvent m_Event = new ManualResetEvent(false);

...

public ulong ExportPacket(string FullPath, global::XXXX.YYY Yyy)

{

NotifyOwner(this, 1, "Инициализация файла");



using(FileStream fs = new FileStream(FullPath, FileMode.Create, FileAccess.ReadWrite))

{

Request req;

NotifyOwner(this, 50, "Запись пакета");

new XmlSerializer(typeof(Request)).Serialize(fs, req = GetYyy(Yyy));



NotifyOwner(this, 100, "Запись завершена");


if (Abyr(Yyy))

{

m_Callback(m_PacketNumber = req.packetHeader.id);

m_Event.Set();



return m_PacketNumber;

}



m_Event.Set();

}



return 0;

}
Так вот, 949 говорит о том, что на выделенной жирным строке форма просто исчезает. При том, что никаких чудес в рассылке уведомлений нет:
public class Notifier

{

private int m_CurrentPercentage;

public event ExportProgressHandler ExportProgress;



protected void NotifyOwner(IExport This, int Percentage, string Text)

{

if (ExportProgress != null)

ExportProgress(This, new ExportEventArgs(m_CurrentPercentage = Percentage, Text));

}



protected void NotifyOwner(IExport This, Inc Increment, string Text)

{

NotifyOwner(This, m_CurrentPercentage + Increment.Value, Text);

}

}
Нет соображений? Не было их и у меня, особенно, если добавить к №949 №954. Интересно и то, что эффект зависел от того, на каком компьютере это собирается (у нас идёт замена железок, сам чёрт сломит...). Мне пришлось разбираться. Самопроизвольное закрытие формы могло быть только в случае установки события в true, но код явно инициализирует его в false. В общем, добавил в Terminate простую диагностику: вывод в лог. Больше ничего не трогал. Собрали на проблемном компьютере - проблемы ушли. И 949 и 954. Цирк? Цирк! И никому не предъявишь. Сейчас вспомнил, что было похожее в VS2003 в статических классах, когда переменная инициализировалась вне статического конструктора. По стандарту это разрешалось, а фактически - переменная получала значение по умолчанию вне зависимости от того, что было написано в инициализаторе. Вот так то. Лучшее средство разработки для .NET. 12 часов долой. Конечно, у нас же их бессчётно.

2 комментария:

Неуловимый Джо комментирует...

Зато какая жизнь интересная.
Насыщенная

Das Ich комментирует...

Зависть - мелкое чувство! ггг