如何测量未选中的选项卡
本文关键字:选项 何测量 测量 | 更新日期: 2023-09-27 17:51:14
简明问题:
是否可以测量未选中选项卡的内容?
问题摘要:
假设您有一个带有两个选项卡的TabControl。第一个选项卡包含一个带有TextBlock的网格。您选择第二个选项卡。一段时间后,TextBlock的Text字段将变为一个很长的字符串。您希望在可见之前测量第一个选项卡内容的大小。
如果你只是简单地进行测量,它不会发现字符串已经更改的事实——你可以在WPF可视化工具中看到,TextBlock的Text字段中有新的字符串,但TextBlock拒绝重新测量。如果直接测量字符串,可以检测到新的所需大小,但这不是一个好的解决方案;我希望能够测量第一个选项卡的总内容,而不仅仅是字符串。
不管怎样,很抱歉有太长的示例代码,这很难进一步减少。当窗口出现时,代码会等待两秒钟,然后交换选项卡。然后它会更改字符串。measure循环在检测到字符串大小更改时将背景更改为蓝色,在检测到实际内容大小更改时则将其更改为红色。红色只在切换标签时发生,但我希望能够在不必切换回第一个标签的情况下发生红色。
代码隐藏:
public MainWindow()
{
InitializeComponent();
// this worker waits a bit so the first tab renders,
// then it switches tabs and changes the string.
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
Thread.Sleep(2000);
Application.Current.Dispatcher.BeginInvoke(new Action(delegate
{
TestTabControl.SelectedIndex = 1;
TestBlock.Text = "This is a long string that ought to change the measure of the textblock to sizes never before seen by human eyes";
this.Background = Brushes.Green;
}));
};
worker.RunWorkerAsync();
// This worker constantly measures the text block
worker = new BackgroundWorker();
worker.DoWork += delegate
{
while (true)
{
if (Application.Current != null)
{
Application.Current.Dispatcher.BeginInvoke(new Action(delegate
{
MeasureFirstTab();
}));
}
else
{
break;
}
Thread.Sleep(100);
}
};
worker.RunWorkerAsync();
}
// Turn the background red when the tab width changes
public void MeasureFirstTab()
{
FirstTabContent.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (MeasureString(TestBlock.Text).Width > 500)
{
this.Background = Brushes.Blue;
}
if (FirstTabContent.DesiredSize.Width > 500)
{
this.Background = Brushes.Red;
}
}
private Size MeasureString(string candidate)
{
var formattedText = new FormattedText(
candidate,
CultureInfo.CurrentUICulture,
FlowDirection.LeftToRight,
new Typeface(TestBlock.FontFamily, TestBlock.FontStyle, TestBlock.FontWeight, TestBlock.FontStretch),
TestBlock.FontSize,
Brushes.Black);
return new Size(formattedText.Width, formattedText.Height);
}
}
XAML:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TabControl Name="TestTabControl">
<TabItem Header="Changes">
<Grid Name="FirstTabContent">
<TextBlock Name="TestBlock" Text="small"/>
</Grid>
</TabItem>
<TabItem Header="Short">
<TextBlock Text="Short"/>
</TabItem>
</TabControl>
</Grid>
为子孙后代和未来在谷歌上搜索它的人回答。
正如我的OP评论中所指出的,TabControl虚拟化了未选择的选项卡,这显然导致度量传递只计算以前所需的大小。
因此,解决方案是从选项卡项目中删除内容,将其添加到网格中,测量内容,然后将其添加回选项卡。
这是新的度量代码:
// Turn the background red when the tab width changes
public void MeasureFirstTab()
{
// Remember the previous selected item
object selectedItem = TestTabControl.SelectedItem;
Grid measureBox = new Grid();
UIElement content;
// Iterate through all items
foreach (TabItem obj in TestTabControl.Items)
{
// Get the tab content into the grid
TestTabControl.SelectedItem = obj;
content = (UIElement)obj.Content;
obj.Content = null;
measureBox.Children.Add(content);
// Measure the content
content.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
if (content.DesiredSize.Width > 500)
{
this.Background = Brushes.Red;
}
// Return the content to its rightful owner
measureBox.Children.Clear();
obj.Content = content;
}
// Reset the tab control
TestTabControl.SelectedItem = selectedItem;
}