2010-01-10 28 views
15

Đoạn sau đây:đáy Align của văn bản trong điều khiển

<Window x:Class="Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <StackPanel Orientation="Horizontal" 
        VerticalAlignment="Center" 
        HorizontalAlignment="Center">    
      <Label Content="Name:"/> 
      <Label Content="Itzhak Perlman" FontSize="44"/> 
     </StackPanel> 
    </Grid> 
</Window> 

ám chỉ rằng sau:
alt text

Có cách nào tôi có thể thiết lập trong phong cách của Nhãn để đáy văn bản của họ nên được liên kết?
Tôi cũng có cùng một câu hỏi với TextBlocks.

LƯU Ý: vì tôi đã gặp khó khăn với vấn đề này trong một thời gian, vui lòng chỉ đăng câu trả lời mà bạn biết rằng công việc.
Tôi đã thử: VerticalAlignment, VerticalContentAlignment, Padding, Margin. Có điều gì khác mà tôi không biết?

Tôi đã đọc bài đăng this nhưng không nói về một kịch bản có kích thước phông chữ khác nhau.

CẬP NHẬT: Vấn đề là, thậm chí Padding được đặt thành 0 vẫn còn một khoảng trống không xác định xung quanh phông chữ, trong vùng ContentPresenter. không gian này khác nhau về kích thước phông chữ. Nếu tôi có thể kiểm soát không gian này, tôi sẽ ở trong tình huống tốt hơn.

Cảm ơn

+1

ah haa! Bản cập nhật của bạn làm rõ vấn đề. –

Trả lời

6

Không có giải pháp chỉ XAML, bạn phải sử dụng mã phía sau. Ngoài ra, ngay cả với mã-đằng sau, không có giải pháp chung cho điều này, bởi vì nếu văn bản của bạn là đa dòng? Đường cơ sở nào nên được sử dụng trong trường hợp đó? Hoặc nếu có nhiều yếu tố văn bản trong mẫu của bạn thì sao? Chẳng hạn như một tiêu đề và nội dung, hoặc nhiều hơn, mà đường cơ sở sau đó?

Tóm lại, đặt cược tốt nhất của bạn là căn chỉnh văn bản theo cách thủ công sử dụng lề trên cùng/dưới cùng.

Nếu bạn sẵn sàng đưa ra giả định rằng bạn có một phần tử văn bản, bạn có thể tìm ra khoảng cách pixel của đường cơ sở từ phía trên của phần tử bằng cách tạo đối tượng FormattedText với tất cả các thuộc tính giống nhau của yếu tố văn bản. Đối tượng FormattedText có thuộc tính doubleBaseline giữ giá trị đó. Lưu ý rằng bạn vẫn sẽ phải nhập thủ công một lề, bởi vì phần tử có thể không được đặt chính xác trên đầu hoặc cuối vùng chứa của nó.

Xem diễn đàn MSDN bài đăng này: Textbox Baseline

Dưới đây là một phương pháp tôi đã viết rằng chiết xuất giá trị đó. Nó sử dụng sự phản chiếu để nhận các thuộc tính có liên quan vì chúng không phổ biến với bất kỳ lớp cơ sở nào (chúng được định nghĩa riêng biệt trên Control, TextBlock, Page, TextElement và có thể là các loại khác).

public double CalculateBaseline(object textObject) 
{ 
    double r = double.NaN; 
    if (textObject == null) return r; 

    Type t = textObject.GetType(); 
    BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public; 

    var fontSizeFI = t.GetProperty("FontSize", bindingFlags); 
    if (fontSizeFI == null) return r; 
    var fontFamilyFI = t.GetProperty("FontFamily", bindingFlags); 
    var fontStyleFI = t.GetProperty("FontStyle", bindingFlags); 
    var fontWeightFI = t.GetProperty("FontWeight", bindingFlags); 
    var fontStretchFI = t.GetProperty("FontStretch", bindingFlags); 

    var fontSize = (double)fontSizeFI.GetValue(textObject, null); 
    var fontFamily = (FontFamily)fontFamilyFI.GetValue(textObject, null); 
    var fontStyle = (FontStyle)fontStyleFI.GetValue(textObject, null); 
    var fontWeight = (FontWeight)fontWeightFI.GetValue(textObject, null); 
    var fontStretch = (FontStretch)fontStretchFI.GetValue(textObject, null); 

    var typeFace = new Typeface(fontFamily, fontStyle, fontWeight, fontStretch); 

    var formattedText = new FormattedText(
     "W", 
     CultureInfo.CurrentCulture, 
     FlowDirection.LeftToRight, 
     typeFace, 
     fontSize, 
     Brushes.Black); 

    r = formattedText.Baseline; 

    return r; 
} 

EDIT: Shimmy, để phản hồi nhận xét của bạn, tôi không tin bạn thực sự đã thử giải pháp này, vì nó hoạt động.Dưới đây là một ví dụ:

Example Baseline Alignment

Dưới đây là các XAML:

<StackPanel> 
    <StackPanel.Resources> 
     <Style TargetType="TextBlock"> 
      <Setter Property="Margin" Value="0,40,0,0"/> 
     </Style> 
    </StackPanel.Resources> 
    <StackPanel Orientation="Horizontal"> 
     <TextBlock Name="tb1" Text="Lorem " FontSize="10"/> 
     <TextBlock Name="tbref" Text="ipsum"/> 
    </StackPanel> 
    <StackPanel Orientation="Horizontal"> 
     <TextBlock Name="tb2" Text="dolor " FontSize="20"/> 
     <TextBlock Text="sit"/> 
    </StackPanel> 
    <StackPanel Orientation="Horizontal"> 
     <TextBlock Name="tb3" Text="amet " FontSize="30"/> 
     <TextBlock Text="consectetuer"/> 
    </StackPanel> 
</StackPanel> 

Và đây là mã đằng sau đó đạt được điều này

double baseRef = CalculateBaseline(tbref); 
double base1 = CalculateBaseline(tb1) - baseRef; 
double base2 = CalculateBaseline(tb2) - baseRef; 
double base3 = CalculateBaseline(tb3) - baseRef; 
tb1.Margin = new Thickness(0, 40 - base1, 0, 0); 
tb2.Margin = new Thickness(0, 40 - base2, 0, 0); 
tb3.Margin = new Thickness(0, 40 - base3, 0, 0); 
+0

@ עדיעד, và tôi phải làm gì với giá trị này? những gì thực sự là 'BaseLine'? – Shimmy

+0

Đường cơ sở là khoảng cách giữa phần đầu của phần tử văn bản và dòng trên đó tất cả các chữ cái 'ngồi'. Ví dụ: nếu bạn đặt lề trên cùng của bạn để nói 50 trừ chênh lệch đường cơ sở, bạn sẽ được đảm bảo căn chỉnh với một dòng cụ thể bất kể kích thước phông chữ. –

+0

Đó là những gì tôi đã thử nhưng không hoạt động. Tôi vẫn đang tìm kiếm giải pháp. Vấn đề là khoảng cách giữa lề và 'đầu văn bản' bạn đề cập đến. Tôi đã cập nhật câu hỏi của mình. Cảm ơn tất cả nỗ lực của bạn. Mọi tin tức? – Shimmy

0

Tôi thực sự tìm thấy một câu trả lời đơn giản dựa trên Aviad 's .

Tôi đã tạo bộ chuyển đổi có chứa chức năng của Aviad chấp nhận chính phần tử đó và trả về Độ dày được tính toán.

Sau đó, tôi lập

<Style TargetType="TextBlock"> 
    <Setter Property="Margin" 
     Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource converters:TextAlignmentMarginConverter}}" /> 
</Style> 

Những bất lợi là điều này rõ ràng là chiếm tài sản Margin gốc, vì một TextBlock không có một khuôn mẫu vì vậy chúng tôi không thể thiết lập nó qua TemplateBinding.

+0

Đó là một cách hay, nhưng trình chuyển đổi sẽ chỉ đưa bạn đi một phần, không phải toàn bộ, bởi vì ví dụ, nếu kích thước phông chữ thay đổi trong khi chạy chương trình, tài sản ký quỹ đã thắng ' Tôi sẽ tự động được đánh giá lại, bạn sẽ phải làm điều đó một cách rõ ràng. Ngoài ra, trình chuyển đổi cần tính đến các phần tử mẫu khác như đệm, đường viền, v.v., do đó bạn vẫn cần chỉnh thủ công (có thể có thông số chuyển đổi). –

+0

Như bạn có thể thấy, tôi đang vượt qua toàn quyền kiểm soát bộ chuyển đổi, vì vậy không cần tham số. Dù sao, tôi hy vọng sẽ cải thiện nó khi tôi sẽ có thời gian. Tôi muốn nó phải được dựa trên chiều cao của cha mẹ vì vậy nó không phải là một giá trị tĩnh như '40'. – Shimmy

5

Tôi thực sự thích các giải pháp sáng tạo được trình bày ở đây nhưng tôi nghĩ rằng trong thời gian dài (ý định chơi chữ) chúng ta nên sử dụng này:

<TextBlock> 
    <Run FontSize="20">What</Run> 
    <Run FontSize="36">ever</Run> 
    <Run FontSize="12" FontWeight="Bold">FontSize</Run> 
</TextBlock> 

Điều duy nhất mà là mất tích từ các yếu tố Run là databinding thuộc tính Text nhưng có thể được thêm sớm hay muộn.

Chạy sẽ không sửa căn chỉnh của nhãn và hộp văn bản nhưng trong nhiều trường hợp đơn giản, Run sẽ hoạt động khá độc đáo.

+0

Hãy nhớ rằng trong nhiều trường hợp, nhãn được ưu tiên để tạo kiểu dễ áp ​​dụng hơn cho nhãn mà không áp dụng cho TextBlocks. Với ví dụ về áp phích ban đầu của 'Tên: TÊN CỦA BẠN TẠI ĐÂY' thì sẽ thích hợp hơn khi sử dụng nhãn để giữ văn bản "Tên:". – jpierson

22

Một giải pháp khá đơn giản khác:

1) Sử dụng điều khiển TextBlock thay cho Nhãn. Lý do là TextBlock có trọng lượng nhẹ hơn Label - xem http://joshsmithonwpf.wordpress.com/2007/07/04/differences-between-label-and-textblock/

2) Sử dụng LineHeight và LineStackingStrategy = BlockLineHeight cho kiểu TextBlock của bạn. Điều này sẽ căn chỉnh hai ở đường cơ sở của họ một cách dễ dàng.

<StackPanel Orientation="Horizontal" 
      VerticalAlignment="Center" 
      HorizontalAlignment="Center"> 
    <StackPanel.Resources> 
     <Style TargetType="TextBlock"> 
      <Setter Property="LineHeight" Value="44pt"/> 
      <Setter Property="LineStackingStrategy" Value="BlockLineHeight"/> 
     </Style> 
    </StackPanel.Resources>    
    <TextBlock Text="Name:"/> 
    <TextBlock Text="Itzhak Perlman" FontSize="44"/> 
</StackPanel> 
+0

@Shimmy bạn đã thử cái này chưa? Nó đơn giản và hiệu quả và nên là câu trả lời. Hoạt động tốt cho tôi. – ygoe

2
<TextBlock> 
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock>Small</TextBlock></InlineUIContainer> 
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock FontSize="50">Big</TextBlock></InlineUIContainer> 
</TextBlock> 

nên này hoạt động tốt. Thử nghiệm với Baseline/Bottom/Center/Top.

1

thiết kế XAML hỗ trợ sắp xếp TextBlock điều khiển bằng cơ sở tại thời gian thiết kế:

enter image description here

này gán lề cố định để kiểm soát của bạn. Miễn là kích thước phông chữ không thay đổi vào thời gian chạy, căn chỉnh sẽ được giữ nguyên.

+0

Có, tính năng này hoạt động. Có lẽ tính năng này không có sẵn tại thời điểm câu hỏi được hỏi (2010) nhưng tôi xác nhận việc sắp xếp có thể được thực hiện theo cách này trong nhà thiết kế WPF trong Viusal Studio 2015 (và rõ ràng là trong một số phiên bản trước đó là ngày của câu trả lời này). Cả hai đối tượng được điều chỉnh * phải chứa văn bản *, vì vậy nếu bạn đang căn chỉnh, ví dụ: Nhãn và TextBox (thường trống), thêm tạm thời một số văn bản bên trong nó. – miroxlav

Các vấn đề liên quan