Criando uma lista de marcadores de vários níveis com o Word.Interop
Eu preciso criar uma lista de marcadores multi-nível viaMicrosoft.Office.Interop.Word
e atualmente estou lutando com sua (horrível) API (novamente).
Acabei de criar o seguinte exemplo (não dinâmico ainda, apenas para fins de demonstração) em um projeto de nível de documento do VSTO para o Microsoft Office Word 2010 na linguagem de programação C #:
Word.Paragraph paragraph = null;
Word.Range range = this.Content;
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = "Item 1";
paragraph.Range.ListFormat.ApplyBulletDefault(Word.WdDefaultListBehavior.wdWord10ListBehavior);
// ATTENTION: We have to outdent the paragraph AFTER its list format has been set, otherwise this has no effect.
// Without this, the the indent of "Item 2" differs from the indent of "Item 1".
paragraph.Outdent();
paragraph.Range.InsertParagraphAfter();
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = "Item 1.1";
// ATTENTION: We have to indent the paragraph AFTER its text has been set, otherwise this has no effect.
paragraph.Indent();
paragraph.Range.InsertParagraphAfter();
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = "Item 1.2";
paragraph.Range.InsertParagraphAfter();
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = "Item 2";
paragraph.Outdent();
O código faz exatamente o que eu quero (depois de muita tentativa e erro!), Mas é horrível na minha opinião. O formato tem que ser aplicado em um ponto muito específico e eu tenho que recuar e desdobrar manualmente os parágrafos criados.
Então minha pergunta é:Existe uma abordagem melhor para criar uma lista de marcadores de vários níveis viaWord.Interop
, por exemplo. via métodos de taquigrafia que ainda não descobri?
Meu objetivo é criar uma lista de vários níveis a partir de dados XML (mais específicosCustomXMLNode
objeto)
Duas outras questões relacionadas a listas com marcadores existem no Stack Overflow, mas ambas não me ajudam (o código fonte acima é uma resposta para a segunda pergunta):
Pontos de bala no Word com c # Interophttps://stackoverflow.com/questions/3768414/ms-word-list-with-sub-listsEDIT (2013-08-08):
Eu acabei de hackear algo que gera dois arrays como uma lista de marcadores com dois níveis (a matriz com os subitens é usada para cada item-raiz, para mantê-lo simples). Ao introduzir a recursão, seria possível criar uma lista de marcadores com níveis infinitos (teoricamente). Mas o problema continua, o código é uma bagunça ...
string[] rootItems = new string[]
{
"Root Item A", "Root Item B", "Root Item C"
};
string[] subItems = new string[]
{
"Subitem A", "Subitem B"
};
Word.Paragraph paragraph = null;
Word.Range range = this.Content;
bool appliedListFormat = false;
bool indented = false;
for (int i = 0; i < rootItems.Length; ++i)
{
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = rootItems[i];
if (!appliedListFormat)
{
paragraph.Range.ListFormat.ApplyBulletDefault(Word.WdDefaultListBehavior.wdWord10ListBehavior);
appliedListFormat = true;
}
paragraph.Outdent();
paragraph.Range.InsertParagraphAfter();
for (int j = 0; j < subItems.Length; ++j)
{
paragraph = range.Paragraphs.Add();
paragraph.Range.Text = subItems[j];
if (!indented)
{
paragraph.Indent();
indented = true;
}
paragraph.Range.InsertParagraphAfter();
}
indented = false;
}
// Delete the last paragraph, since otherwise the list ends with an empty sub-item.
paragraph.Range.Delete();
EDIT (2013-08-12):
Na última sexta-feira, achei que consegui o que queria, mas esta manhã notei que minha solução só funciona se o ponto de inserção estiver no final do documento. Eu criei o seguinte exemplo simples para demonstrar o comportamento (errôneo). Para concluir meu problema: sou capaz de criar listas com marcadores de vários níveis no final do documentosó. Assim que eu alterar a seleção atual (por exemplo, para o início do documento), a lista é destruída. Tanto quanto eu posso ver, isso está relacionado com a extensão (automática ou não automática) doRange
objetos. Eu tentei muito até agora (eu estou quase perdendo isso), mas é todo o culto da carga para mim. A única coisa que quero fazer é inserir um elemento após o outro (é impossível criar um controle de conteúdodentro um parágrafo, para que o texto do parágrafo seja seguido pelo controle de conteúdo?)e para isso em qualquerRange
de umDocument
. Vou criar uma Gist no GitHub com o meu realCustomXMLPart
aula obrigatória esta noite. Eventualmente, alguém pode me ajudar a consertar esse problema incômodo.
private void buttonTestStatic_Click(object sender, RibbonControlEventArgs e)
{
Word.Range range = Globals.ThisDocument.Application.Selection.Range;
Word.ListGallery listGallery = Globals.ThisDocument.Application.ListGalleries[Word.WdListGalleryType.wdBulletGallery];
Word.Paragraph paragraph = null;
Word.ListFormat listFormat = null;
// TODO At the end of the document, the ranges are automatically expanded and inbetween not?
paragraph = range.Paragraphs.Add();
listFormat = paragraph.Range.ListFormat;
paragraph.Range.Text = "Root Item A";
this.ApplyListTemplate(listGallery, listFormat, 1);
paragraph.Range.InsertParagraphAfter();
paragraph = paragraph.Range.Paragraphs.Add();
listFormat = paragraph.Range.ListFormat;
paragraph.Range.Text = "Child Item A.1";
this.ApplyListTemplate(listGallery, listFormat, 2);
paragraph.Range.InsertParagraphAfter();
paragraph = paragraph.Range.Paragraphs.Add();
listFormat = paragraph.Range.ListFormat;
paragraph.Range.Text = "Child Item A.2";
this.ApplyListTemplate(listGallery, listFormat, 2);
paragraph.Range.InsertParagraphAfter();
paragraph = paragraph.Range.Paragraphs.Add();
listFormat = paragraph.Range.ListFormat;
paragraph.Range.Text = "Root Item B";
this.ApplyListTemplate(listGallery, listFormat, 1);
paragraph.Range.InsertParagraphAfter();
}
private void ApplyListTemplate(Word.ListGallery listGallery, Word.ListFormat listFormat, int level = 1)
{
listFormat.ApplyListTemplateWithLevel(
listGallery.ListTemplates[level],
ContinuePreviousList: true,
ApplyTo: Word.WdListApplyTo.wdListApplyToSelection,
DefaultListBehavior: Word.WdDefaultListBehavior.wdWord10ListBehavior,
ApplyLevel: level);
}
EDIT (2013-08-12): Eu configurei um repositório do GitHubAqui o que demonstra o meu problema com oWord.Range
objetos. oOnClickButton
método no arquivoRibbon.cs
invoca minha classe de mapeador personalizado. Os comentários lá descrevem o problema. Euconhecer que meus problemas estão relacionados ao argumentoWord.Range
referência de objeto, mas todas as outras soluções que tentei (por exemplo, modificar o intervalo dentro da classe) falharam ainda mais. A melhor solução que consegui até agora, é especificar oDocument.Content
gama como o argumento para oMapToCustomControlsIn
método. Isso insere uma lista de marcadores de vários níveis bem formatada (com partes XML personalizadas vinculadas a controles de conteúdo)fim do documento. O que eu quero é inserir essa listaem uma posição personalizada no documento (por exemplo, a seleção atual viaWord.Selection.Range
).