Удаление (или обновление) изображения из RichTextBox - PullRequest
1 голос
/ 17 июля 2009

У меня есть вопрос, связанный с управлением объектами OLE в RichTextBox.

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

1. Что я знаю до сих пор

Прежде всего, я использую OLE для вставки изображений (или любого ActiveX) в RichTextBox. Предполагается, что это «правильный путь», поскольку в нем нет буфера обмена, и вы можете вставить любой элемент управления ActiveX, какой захотите. В CodeProject есть статья ( MyExtRichTextBox ), в которой объясняется, как это сделать (с полным исходным кодом), но для краткости:

Используя P / Invoke, функция OleCreateFromFile импортируется из ole32.dll для создания объекта OLE из файла изображения.

int hresult = OleCreateFromFile(...);

Функция возвращает экземпляр IOleObject, на который затем должна ссылаться структура REOBJECT:

REOBJECT reoObject = new REOBJECT();

reoObject.cp = 0; // charated index for insertion
reoObject.clsid = guid; // iOleObject class guid
reoObject.poleobj = Marshal.GetIUnknownForObject(pOleObject); // actual object

// etc. (set other fields

// Then we set the flags. We can, for example, make the image resizable 
// by adding a flag. I found this question to be asked frequently
// (how to enable or disable image drag handles).
reoObject.dwFlags = (uint)
     (REOOBJECTFLAGS.REO_BELOWBASELINE | REOOBJECTFLAGS.REO_RESIZABLE);

// and I use the `dwUser` property to set the object's unique id 
// (it's a 32-bit word, and it will be sufficient to identify it)
reoObject.dwUser = id;

И, наконец, структура передается RichTextBox с помощью IRichEditOle.InsertObject. IRichEditOle - это интерфейс COM, также импортированный с помощью P / Invoke.

«Идентификатор» для объекта позволяет мне перебирать список вставленных объектов и «делать вещи». Используя IRichEditOle.GetObject, я могу получить каждый вставленный объект и проверить поле dwUser, чтобы убедиться, что идентификатор совпадает.

2. Проблемы

Теперь перейдем к вопросам:

a) Первая проблема - обновление вставленного изображения. Я хочу иметь возможность «обновлять» определенные изображения по требованию (или изменять их). То, как я сейчас это делаю, выглядит примерно так:

if (reoObject.dwUser == id)
{
    // get the char index for the "old" image
    oldImageIndex = reoObject.cp;

    // insert the new image (I added this overload for testing,
    // it does the thing described above)
    InsertImageFromFile(oldImageIndex, id, filename);

    // and now I select the old image (which has now moved by one "character"
    // position to the right), and delete it by setting the selection to ""
    _richEdit.SelectionStart = oldImageIndex + 1;
    _richEdit.SelectionLength = 1;
    _richEdit.SelectedText = "";
}

Поскольку я обновляю из потока Gui, я думаю, что мне не стоит беспокоиться о том, что пользователь изменяет выбор во время этого метода, потому что вставка OLE блокирует поток, и приложение работает в STA.

Но я как-то чувствую, что может быть лучший / более безопасный способ сделать это? Этот метод выглядит так, как будто я должен пометить его атрибутом [DirtyHack].

b) Другая проблема заключается в том, что в момент вставки (IRichEditOle.InsertObject) я получаю необработанное исключение (Paint Shop Pro перестал работать). Кажется, что вставка объекта OLE каким-то образом запускает это приложение, хотя для команд оболочки Open или Edit не существует ассоциаций файлов.

Кто-нибудь знает, что может быть причиной и как ее предотвратить?

[Изменить]

У меня просто другая идея - я могу создать свой собственный элемент управления ActiveX, который позаботится об обновлении изображения. В этом случае мне нужно будет только аннулировать эту часть RichTextBox (аналогично тому, что делает автор статьи CodeProject). Но это усложнит развертывание (мне нужно открыть класс .Net для COM, а затем зарегистрировать его перед внедрением).

1 Ответ

0 голосов
/ 17 июля 2009

Я не так много знаю о .NET / OLE / ActiveX и т. Д., Но при программировании GUI вам следует избегать изменения / обновления окон из потоков.

У меня был похожий опыт работы с C ++. Вместо того, чтобы использовать поток для изменения вашего окна, вы должны использовать что-то вроде таймера.

...