Po ustawieniu opcji TextWrapping na "Wrap", blokowanie tekstu WPF może mieć kilka wierszy tekstu. Czy istnieje "czysty" sposób na uzyskanie liczby linii tekstu? Rozważałem, patrząc na pożądaną wysokość i dzieląc ją przez szacunkową wysokość każdej linii. Jednak wydaje się to dość brudne. Czy istnieje lepszy sposób?Widoczna liczba wierszy obiektu TextBlock
Odpowiedz
Jedną z cech WPF jest to, że wszystkie elementy sterujące są bardzo nieskazitelne. Z tego powodu możemy skorzystać z TextBox, która ma właściwość LineCount (Dlaczego to nie jest DependencyProperty lub dlaczego TextBlock również go nie ma, nie wiem). Za pomocą TextBox możemy po prostu zmienić szablon, aby zachowywał się i wyglądał bardziej jak TextBlock. W naszym niestandardowym stylu/szablonie ustawimy IsEnabled na False i po prostu utworzymy podstawową zmianę struktury kontrolki, aby wyłączony wygląd nie był już obecny. Możemy również powiązać dowolne właściwości, które chcemy zachować, takie jak tło, za pomocą TemplateBindings.
<Style x:Key="Local_TextBox"
TargetType="{x:Type TextBoxBase}">
<Setter Property="IsEnabled"
Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border Name="Border"
Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
teraz, że zadba o to, ze nasz TextBox wyglądają i zachowują się jak TextBlock, ale w jaki sposób dostać się liczyć linia?
Cóż, jeśli chcemy uzyskać do niego dostęp bezpośrednio w kodzie, możemy zarejestrować się w wydaniu SizeChanged w TextBox.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LongText = "This is a long line that has lots of text in it. Because it is a long line, if a TextBlock's TextWrapping property is set to wrap then the text will wrap onto new lines. However, we can also use wrapping on a TextBox, that has some diffrent properties availible and then re-template it to look just like a TextBlock!";
uiTextBox.SizeChanged += new SizeChangedEventHandler(uiTextBox_SizeChanged);
this.DataContext = this;
}
void uiTextBox_SizeChanged(object sender, SizeChangedEventArgs e)
{
Lines = uiTextBox.LineCount;
}
public string LongText { get; set; }
public int Lines
{
get { return (int)GetValue(LinesProperty); }
set { SetValue(LinesProperty, value); }
}
// Using a DependencyProperty as the backing store for Lines. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LinesProperty =
DependencyProperty.Register("Lines", typeof(int), typeof(MainWindow), new UIPropertyMetadata(-1));
}
Jednakże, ponieważ staram się trzeba użyć właściwości takiego w miejscach innych ówczesnych bieżącego okna i/lub używam MVVM i nie chcą podjąć takie podejście, to możemy stworzyć kilka AttachedProperties do obsłużyć pobieranie i ustawienie LineCount. Zamierzamy użyć AttachedProperties, aby zrobić to samo, ale teraz będziemy mogli użyć go z dowolnym tekstem TextBox w dowolnym miejscu i powiązać go za pomocą tego TextBox zamiast DataContext okna.
public class AttachedProperties
{
#region BindableLineCount AttachedProperty
public static int GetBindableLineCount(DependencyObject obj)
{
return (int)obj.GetValue(BindableLineCountProperty);
}
public static void SetBindableLineCount(DependencyObject obj, int value)
{
obj.SetValue(BindableLineCountProperty, value);
}
// Using a DependencyProperty as the backing store for BindableLineCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BindableLineCountProperty =
DependencyProperty.RegisterAttached(
"BindableLineCount",
typeof(int),
typeof(MainWindow),
new UIPropertyMetadata(-1));
#endregion // BindableLineCount AttachedProperty
#region HasBindableLineCount AttachedProperty
public static bool GetHasBindableLineCount(DependencyObject obj)
{
return (bool)obj.GetValue(HasBindableLineCountProperty);
}
public static void SetHasBindableLineCount(DependencyObject obj, bool value)
{
obj.SetValue(HasBindableLineCountProperty, value);
}
// Using a DependencyProperty as the backing store for HasBindableLineCount. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HasBindableLineCountProperty =
DependencyProperty.RegisterAttached(
"HasBindableLineCount",
typeof(bool),
typeof(MainWindow),
new UIPropertyMetadata(
false,
new PropertyChangedCallback(OnHasBindableLineCountChanged)));
private static void OnHasBindableLineCountChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var textBox = (TextBox)o;
if ((e.NewValue as bool?) == true)
{
textBox.SetValue(BindableLineCountProperty, textBox.LineCount);
textBox.SizeChanged += new SizeChangedEventHandler(box_SizeChanged);
}
else
{
textBox.SizeChanged -= new SizeChangedEventHandler(box_SizeChanged);
}
}
static void box_SizeChanged(object sender, SizeChangedEventArgs e)
{
var textBox = (TextBox)sender;
(textBox).SetValue(BindableLineCountProperty, (textBox).LineCount);
}
#endregion // HasBindableLineCount AttachedProperty
}
teraz, to proste, aby znaleźć LineCount:
<StackPanel>
<TextBox x:Name="uiTextBox"
TextWrapping="Wrap"
local:AttachedProperties.HasBindableLineCount="True"
Text="{Binding LongText}"
Style="{StaticResource Local_TextBox}" />
<TextBlock Text="{Binding Lines, StringFormat=Binding through the code behind: {0}}" />
<TextBlock Text="{Binding ElementName=uiTextBox, Path=(local:AttachedProperties.BindableLineCount), StringFormat=Binding through AttachedProperties: {0}}" />
</StackPanel>
Prostym sposobem jest własnością LineCount. Masz również metodę o nazwie GetLastVisibleLineIndex, która informuje, ile linii może wyświetlać pole tekstowe (bez pasków przewijania).
Jeśli chcesz wiedzieć, kiedy linia jest dodawana, możesz usłyszeć w zdarzeniu TextChanged i zapytać o właściwość LineCount (aby porównać, musisz zachować wartość LineCount dla lasów).
TextBlock nie ma właściwości LineCount. To wyłącznie domena TextBox. –
Znalazłem to przydatne. dobra informacja, zła odpowiedź. – mdw7326
// this seems to do the job
<TextBox x:Name="DescriptionTextBox"
Grid.Row="03"
Grid.RowSpan="3"
Grid.Column="01"
Width="100"
AcceptsReturn="True"
MaxLength="100"
MaxLines="3"
PreviewKeyDown="DescriptionTextBox_PreviewKeyDown"
Text="{Binding Path=Description,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
TextWrapping="Wrap" />
/// <summary>
/// we need to limit a multi line textbox at entry time
/// </summary>
/// <param name="sender">
/// The sender.
/// </param>
/// <param name="e">
/// The e.
/// </param>
private void DescriptionTextBox_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
TextBox thisTextBox = sender as TextBox;
if (thisTextBox != null)
{
// only check if we have passed the MaxLines
if (thisTextBox.LineCount > thisTextBox.MaxLines)
{
// we are going to discard the last entered character
int numChars = thisTextBox.Text.Length;
// force the issue
thisTextBox.Text = thisTextBox.Text.Substring(0, numChars - 1);
// set the cursor back to the last allowable character
thisTextBox.SelectionStart = numChars - 1;
// disallow the key being passed in
e.Handled = true;
}
}
}
Pytanie dotyczyło TextBlock a nie TextBox. – jHilscher
Widziałem, że ta kwestia jest już 7 lat, ale ja po prostu przyszedł z roztworem:
TextBlock dysponują właściwość o nazwie LineCount. Stworzyłem metodę rozszerzenia, aby odczytać tę wartość:
public static class TextBlockExtension
{
public static int GetLineCount(this TextBlock tb)
{
var propertyInfo = GetPrivatePropertyInfo(typeof(TextBlock), "LineCount");
var result = (int)propertyInfo.GetValue(tb);
return result;
}
private static PropertyInfo GetPrivatePropertyInfo(Type type, string propertyName)
{
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.NonPublic);
return props.FirstOrDefault(propInfo => propInfo.Name == propertyName);
}
}
- 1. Przewijanie obiektu TextBlock
- 2. Liczba wierszy w RDD
- 3. Przygotowane instrukcje - liczba wierszy
- 4. liczba liczba wierszy w szablonach kolby
- 5. Stylizacja obiektu Textblock utworzonego w programie ContentPresenter
- 6. Liczba wierszy SQLBulkCopy po ukończeniu
- 7. SQL DELETE - Maksymalna liczba wierszy
- 8. Liczba wierszy w arkuszu roboczym
- 9. Liczba wierszy w każdej grupie
- 10. Liczba wierszy w tablicy numpy
- 11. Liczba wierszy w pliku CSV
- 12. Liczba wierszy SQL w tabeli
- 13. TextBlock Text Wiązanie właściwości ObservableCollection.Count
- 14. Liczba wierszy, w której istnieją dane
- 15. Liczba wierszy Matlaba w pliku Excel
- 16. Dynamiczna liczba wierszy w Laravel Blade
- 17. Maksymalna liczba wierszy w tabeli sqlite?
- 18. Liczba wierszy rodziny kolumn w Cassandra
- 19. MYSQL - liczba wierszy w każdej tabeli
- 20. Liczba wierszy na grupę w mysql
- 21. Liczba wierszy hibernacji z pewnymi kryteriami:
- 22. Nieprawidłowa aktualizacja: nieprawidłowa liczba wierszy w sekcji
- 23. Liczba grupy według wierszy w hibernacji kryteriów
- 24. Jak zmierzyć rozmiar obiektu TextBlock w WPF przed renderowaniem?
- 25. Formatowanie części tekstu obiektu TextBlock za pomocą iValueConverter
- 26. UILabel widoczna część tekstu
- 27. Priorytetowa zawartość widoczna Wordpress
- 28. C# UserControl Widoczna właściwość
- 29. Dostęp kolor tła textblock
- 30. Wiązanie tekstu WPF TextBlock
To jest świetne. Jednak TextBox są bardziej ograniczone niż TextBlock, ponieważ mają jednolitą rodzinę czcionek/rozmiar czcionki. W rezultacie łatwo obliczyć liczbę linii. Z drugiej strony TextBlocks mogą mieć różne inline o różnych wysokościach. To sprawia, że rzeczy nieco trudniejsze. – tom7