2010-03-26 73 views
4

我試圖重現的一些紙質表格佈局在WPF應用程序。文本框的標籤應與文本框的內容「內聯」,而不是像正常的Windows窗體那樣「外部」。因此,與XXXXXX標籤:內嵌文本框的標籤與WPF

+-----------------------------+ 
| Xxxxxx: some text written | 
| in the multiline input.  | 
|        | 
| another paragraph continues | 
| without indentation.  | 
|        | 
|        | 
+-----------------------------+ 

的XXXXXX不能編輯,如果用戶選擇的文本框中的所有內容,標籤必須保留不選,我需要能夠樣式化文本的顏色/格式當文本框中沒有文本但它具有焦點時,脫字符應該在標籤後面閃爍,並且我需要文本框中的文本的基線和標籤對齊。

一個解決方法我試過是把一個文本塊部分地輸入,然後使用文本縮進縮進可編輯的文本,雖然這導致與下面的段落中的問題,因爲他們太縮進。我不確定如何縮進第一段。它需要一些擺弄才能使文本排列起來 - 更可靠的設置將是理想的。

因此,在任何建議,如何設置呢?

謝謝

回答

1

嗯,我可以建議一個有點ha way的方法來做到這一點。

首先,請注意,你可以把UI元素成FlowDocument。這樣就使得這樣的可能:

<RichTextBox> 
    <FlowDocument> 
    <Paragraph> 
     <InlineUIContainer> 
     <TextBlock>This is your label: </TextBlock> 
     </InlineUIContainer> 
     <Run>And this is the editable text.</Run> 
    </Paragraph> 
    </FlowDocument> 
</RichTextBox> 

現在的問題變成,從編輯InlineUIContainer保持用戶。這實際上是兩個問題。

第一個問題是從保持用戶選擇它。要做到這一點,你必須處理SelectionChanged事件。如果發現RTB文檔中的第一個InlineUIContainer,並且如果Selection.Start在此之前,請更改它。

private void RichTextBox_SelectionChanged(object sender, RoutedEventArgs e) 
{ 
    RichTextBox rtb = (RichTextBox) sender; 
    if (rtb == null) return; 

    InlineUIContainer c = rtb.Document 
     .Blocks 
     .Where(x => x is Paragraph) 
     .Cast<Paragraph>() 
     .SelectMany(x => x.Inlines) 
     .Where(x => x is InlineUIContainer) 
     .Cast<InlineUIContainer>() 
     .FirstOrDefault(); 

    if (c == null) return; 

    if (rtb.Selection.Start.CompareTo(c.ElementEnd) < 0) 
    { 
     rtb.Selection.Select(c.ElementEnd, rtb.Selection.End); 
    } 
} 

有可能是一種更簡單的方式來制定該LINQ查詢,但我有點喜歡它。這不是100%完美;如果您在文字內部選擇並向左拖動TextBlock,則會丟失選擇。我相信這可以修復。但它工作得很好。它甚至可以處理用戶使用箭頭鍵導航的情況。

就這麼多讓你有幾乎所有的方式。但是,另一件可能會讓你煩惱的事情是,如果用戶將光標置於文本的開頭並按下BACKSPACE。

處理,需要類似的東西:比較與第一InlineUIElement結束的插入位置,並取消Backspace鍵(通過標記爲處理該事件)如果光標的在該位置:

private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e) 
{ 
    if (e.Key != Key.Back) 
    { 
     return; 
    } 

    RichTextBox rtb = (RichTextBox)sender; 
    if (rtb == null) return; 

    InlineUIContainer c = rtb.Document 
     .Blocks 
     .Where(x => x is Paragraph) 
     .Cast<Paragraph>() 
     .SelectMany(x => x.Inlines) 
     .Where(x => x is InlineUIContainer) 
     .Cast<InlineUIContainer>() 
     .FirstOrDefault(); 

    if (c == null) return; 

    if (rtb.CaretPosition.CompareTo(c.ElementEnd.GetInsertionPosition(LogicalDirection.Forward)) <= 0) 
    { 
     e.Handled = true; 
    }    
}