我有一个带Text属性的视图模型。视图模型实现了INotifyPropertyChanged。
public string Text
{
get { return _text; }
set
{
_text = value;
NotifyPropertyChanged("Text");
}
}
private string _text;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
DataTemplate在TextBlock中显示视图模型的Text。文本块已打开包装。
<DataTemplate DataType="{x:Type viewModels:TextViewModel}">
<Grid Width="{Binding Path=Width, Mode=OneWay}"
Height="{Binding Path=Height, Mode=OneWay}">
<TextBlock Text="{Binding Path=Text, Mode=OneWay}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
TextAlignment="Left"/>
</Grid>
</DataTemplate>
我要求显示在另一个视图中修剪的任何文本。例如,如果我的文字是&#34;只是一些文字&#34;只有&#34;只是一些&#34;显示我需要显示&#34; text&#34;在另一种观点。是否有一种简单的方法可以让视图模型确定屏幕上显示的内容,而不知道文本是否显示在带有文本换行的TextBlock中?
我已经看过在视图模型中使用FormattedText类。但是,它需要大量信息,视图模型不具有字体和字体大小。
答案 0 :(得分:1)
在我看来,viewmodel不是完成它的正确位置。 viewmodel只包含视图的数据。视图显示的是一个观点。如果文本被修剪,则仅显示第一部分。您可以在视图的某些事件处理程序中处理它。其他一些视图可以绑定到同一个视图模型。在另一个视图中,您可以更改仅显示另一方的事件处理程序。
为了减少重复,您可以定义一个包含此功能的用户控件。
无论如何你应该检查你的要求,听起来不是很安静,但这只是我的意见; - )
答案 1 :(得分:0)
@NETscape提供的link向我指出了正确的方向。该链接指向another page,其中讨论了使用attached properties在TextBlock上公开IsTextWrapped属性。我想出了一种暴露修剪指数的类似方法。
我创建了一个静态类来公开一个属性,该属性包含发生包装的索引。另一个属性启用或禁用索引的计算。对于我的情况,我只需要知道在几个场景中发生包装的位置。我正在使用TextBlock的Loaded事件计算HiddenTextIndex。这只能起作用,因为我知道文本不会在视图的上下文中发生变化。我确实需要重构将数据提供给我的视图模型的代码,以确保在最初加载后不需要更改。
public static class TextBlockWrapService
{
public static readonly DependencyProperty IsWrapAwareProperty =
DependencyProperty.RegisterAttached("IsWrapAware", typeof(bool), typeof(TextBlockWrapService),
new PropertyMetadata(false, IsWrapAwarePropertyChanged));
public static readonly DependencyProperty HiddenTextIndexProperty =
DependencyProperty.RegisterAttached("HiddenTextIndex", typeof(int), typeof(TextBlockWrapService),
new PropertyMetadata(-1));
public static bool GetIsWrapAware(TextBlock block)
{
if (block == null)
return false;
return (bool)block.GetValue(IsWrapAwareProperty);
}
public static void SetIsWrapAware(TextBlock block, bool value)
{
if (block == null)
return;
block.SetValue(IsWrapAwareProperty, value);
}
public static int GetHiddenTextIndex(TextBlock block)
{
if (!GetIsWrapAware(block))
return -1;
return (int)block.GetValue(HiddenTextIndexProperty);
}
public static void SetHiddenTextIndex(TextBlock block, int value)
{
if (block == null)
return;
block.SetValue(HiddenTextIndexProperty, value);
}
private static void IsWrapAwarePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var block = d as TextBlock;
if (block == null || e.NewValue == null)
return;
bool wrapAware;
if (!bool.TryParse(e.NewValue.ToString(), out wrapAware))
return;
if (wrapAware)
block.Loaded += TextBlock_Loaded;
else
block.Loaded -= TextBlock_Loaded;
}
private static void TextBlock_Loaded(object sender, RoutedEventArgs e)
{
UpdateHiddenTextIndex(sender as TextBlock);
}
private static void UpdateHiddenTextIndex(TextBlock block)
{
if (block == null)
return;
if (!GetIsWrapAware(block) || block.TextTrimming == TextTrimming.None)
SetHiddenTextIndex(block, -1);
else
SetHiddenTextIndex(block, CalculateHiddenTextIndex(block));
}
public static int CalculateHiddenTextIndex(TextBlock block)
{
var typeface = new Typeface(block.FontFamily,
block.FontStyle,
block.FontWeight,
block.FontStretch);
if (string.IsNullOrWhiteSpace(block.Text) ||
block.ActualHeight <= 1 ||
!TextIsTrimmedAtLength(block, typeface, block.Text.Length) ||
TextIsTrimmedAtLength(block, typeface, 0))
return -1;
var untrimmedLength = 1;
var trimmedLength = block.Text.Length;
while (untrimmedLength < trimmedLength - 1)
{
var untestedLength = (trimmedLength + untrimmedLength) / 2;
if (untestedLength <= untrimmedLength || untestedLength >= trimmedLength)
break;
if (TextIsTrimmedAtLength(block, typeface, untestedLength))
trimmedLength = untestedLength;
else
untrimmedLength = untestedLength;
}
return untrimmedLength;
}
private static bool TextIsTrimmedAtLength(TextBlock block, Typeface typeface, int length)
{
var formattedText = new FormattedText(block.Text.Substring(0, length),
Thread.CurrentThread.CurrentCulture,
block.FlowDirection,
typeface,
block.FontSize,
block.Foreground) { MaxTextWidth = block.ActualWidth };
return formattedText.Height > block.ActualHeight;
}
}
IsWrapAware将允许我仅在需要时计算索引。 HiddenTextIndex是发生包装的索引。 HiddenTextIndex通过xaml中的绑定传递给视图模型。
<DataTemplate DataType="{x:Type viewModels:TextViewModel}">
<Grid Width="{Binding Path=Width, Mode=OneWay}"
Height="{Binding Path=Height, Mode=OneWay}">
<TextBlock Text="{Binding Path=Text, Mode=OneWay}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
TextAlignment="Left"
utility:TextBlockWrapService.IsWrapAware="True"
utility:TextBlockWrapService.HiddenTextIndex="{Binding Path=HiddenTextIndex, Mode=OneWayToSource}"/>
</Grid>
</DataTemplate>
视图模型上有相应的HiddenTextIndex属性。此时我可以使用Substring来确定隐藏的内容和显示的内容。