문제
다음 스 니펫 :
<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>
다음을 렌더링합니다.
라벨 스타일을 설정하여 텍스트 하단을 정렬 해야하는 방법이 있습니까?
TextBlock과 같은 질문도 있습니다.
참고 :이 문제로 한동안 어려움을 겪고 있기 때문에 그 일을 알고 있다는 특정 답변 만 게시하십시오.
나는 이미 시도했다 : 수직 정렬, verticalContentalIngment, 패딩, 마진. 내가 알지 못하는 다른 것이 있습니까?
나는 읽었다 이것 게시물이지만 다른 글꼴 크기의 시나리오에 대해서는 이야기하지 않습니다.
업데이트: 문제는 패딩조차도 0으로 설정되어 있다는 것입니다. 콘텐츠 프레 센터 영역 내에 글꼴 주변에 불확실한 공간이 여전히 있다는 것입니다. 이 공간은 글꼴 크기에 따라 다릅니다. 이 공간을 통제 할 수 있다면 더 나은 상황에 처할 것입니다.
감사
해결책
XAML 전용 솔루션이 없으므로 코드를 사용해야합니다. 또한 Code-Behind를 사용하더라도 이에 대한 일반적인 해결책은 없습니다. 텍스트가 멀티 라인이라면 어떨까요? 이 경우 어떤 기준선을 사용해야합니까? 아니면 템플릿에 여러 텍스트 요소가 있으면 어떻게됩니까? 헤더 및 컨텐츠 또는 그 이상과 같은 기준선과 같은?
요컨대, 가장 좋은 방법은 상단/하단 마진을 사용하여 수동으로 텍스트를 정렬하는 것입니다.
단일 텍스트 요소가 있다고 가정하면 기준선의 픽셀 거리를 인스턴스화하여 요소의 상단에서 파악할 수 있습니다. FormattedText
기존 텍스트 요소와 동일한 속성을 가진 객체. 그만큼 FormattedText
물체에는 a가 있습니다 double
Baseline
그 가치를 보유한 속성. 요소가 컨테이너의 상단 또는 하단에 정확하게 앉아 있지 않을 수 있으므로 여전히 수동으로 마진을 입력해야합니다.
이 MSDN 포럼 게시물을 참조하십시오. 텍스트 상자 기준선
다음은 그 값을 추출하는 방법입니다. 단일 기본 클래스에 공통적이지 않기 때문에 관련 속성을 얻기 위해 반사를 사용합니다 (별도로 정의됩니다. Control
, TextBlock
, Page
, TextElement
그리고 아마도 다른 사람들).
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;
}
편집 : Shimmy, 귀하의 의견에 대한 응답으로, 나는 당신이 실제로이 솔루션이 작동하기 때문에 실제로 시도했다고 생각하지 않습니다. 예는 다음과 같습니다.
여기 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>
그리고 여기에 이것을 달성하는 코드가 있습니다
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);
다른 팁
상당히 간단한 솔루션 :
1) 레이블 대신 텍스트 블록 컨트롤을 사용하십시오. 텍스트 블록이 레이블보다 가벼운 무게이기 때문입니다. http://joshsmithonwpf.wordpress.com/2007/07/04/differences-between-label-and-textblock/
2) TextBlock 스타일에 LineHeight 및 Linestackingstrategy = BlockLineHeight를 사용하십시오. 이것은 두 가지를 기준선에서 쉽게 맞출 것입니다.
<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>
나는 여기에 제시된 창의적인 솔루션을 정말 좋아하지만 장기적으로 (말장난 의도) 우리는 이것을 사용해야한다고 생각합니다.
<TextBlock>
<Run FontSize="20">What</Run>
<Run FontSize="36">ever</Run>
<Run FontSize="12" FontWeight="Bold">FontSize</Run>
</TextBlock>
실행 요소에서 누락 된 유일한 것은 텍스트 속성의 데이터베이닝이지만 조만간 추가 될 수 있습니다.
실행은 레이블과 텍스트 상자의 정렬을 수정하지 않지만 많은 간단한 상황에서 실행은 상당히 멋지게 수행됩니다.
<TextBlock>
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock>Small</TextBlock></InlineUIContainer>
<InlineUIContainer BaselineAlignment="Baseline"><TextBlock FontSize="50">Big</TextBlock></InlineUIContainer>
</TextBlock>
이것은 잘 작동합니다. 기준선/하단/센터/상단 실험.
XAML 디자이너는 정렬을 지원합니다 TextBlock
설계 시간에 기준선별 컨트롤 :
이것은 당신의 컨트롤에 고정 마진을 할당합니다. 글꼴 크기가 런타임에 변하지 않는 한 정렬이 보존됩니다.
실제로 간단한 답변을 찾았습니다 Aviad'에스.
요소 자체를 받아들이고 계산 된 두께를 반환하는 Aviad의 기능이 포함 된 변환기를 만들었습니다.
그런 다음 설정했습니다
<Style TargetType="TextBlock">
<Setter Property="Margin"
Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource converters:TextAlignmentMarginConverter}}" />
</Style>
단점은 TextBlock에 템플릿이 없으므로 TemplateBinding을 통해 설정할 수 없기 때문에 원래 마진 속성을 차지한다는 것입니다.