要回答您的问题:
Dispatcher.BeginInvoke()
将调度程序的“待处理作业”队列中的操作排队。这允许它能够处理添加的第一个 UI 元素,并在继续执行代码之前运行Layout
和传递。Render
因此,当你的代码运行时,第一个 TextBlock 的大小已经计算出来了,你可以得到它。
同样,我不知道您要做什么,但在代码中创建 UI 元素通常是设计不佳的标志。WPF 不是 winforms,WPF 方式与在 winforms 中做任何事情所需的可怕黑客完全不同。
编辑:
这是我使用 aWrapPanel
和 some的方法RenderTransform
:
<Window x:Class="MiscSamples.MovingWords"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MovingWords" Height="300" Width="300">
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Thumb DragDelta="Thumb_DragDelta" Margin="2">
<Thumb.Template>
<ControlTemplate>
<TextBlock Text="{Binding Text}"
FontSize="{Binding FontSize}"
Foreground="{Binding Color}"/>
</ControlTemplate>
</Thumb.Template>
<Thumb.RenderTransform>
<TranslateTransform X="{Binding OffsetX}" Y="{Binding OffsetY}"/>
</Thumb.RenderTransform>
</Thumb>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
代码背后:
public partial class MovingWords : Window
{
public ObservableCollection<MovingWordModel> Words { get; set; }
public MovingWords()
{
InitializeComponent();
Words = new ObservableCollection<MovingWordModel>
{
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "Hello!!"},
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "This"},
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "is"},
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "the"},
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "Power"},
new MovingWordModel() {Color = "Black", FontSize = 18, Text = "of"},
new MovingWordModel() {Color = "Blue", FontSize = 18, Text = "WPF"},
};
DataContext = Words;
}
private void Thumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
{
var thumb = sender as Thumb;
if (thumb == null)
return;
var word = thumb.DataContext as MovingWordModel;
if (word == null)
return;
word.OffsetX += e.HorizontalChange;
word.OffsetY += e.VerticalChange;
}
}
数据模型:
public class MovingWordModel:PropertyChangedBase
{
public string Text { get; set; }
public int FontSize { get; set; }
public string Color { get; set; }
private double _offsetX;
public Double OffsetX
{
get { return _offsetX; }
set
{
_offsetX = value;
OnPropertyChanged("OffsetX");
}
}
private double _offsetY;
public double OffsetY
{
get { return _offsetY; }
set
{
_offsetY = value;
OnPropertyChanged("OffsetY");
}
}
}
属性更改基础:
public class PropertyChangedBase:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
您可以单击并拖动单词以移动它们。
请注意,拖动的值将存储在OffsetX
和OffsetY
属性中。这种方法的唯一问题是您在某种程度上失去了分辨率独立性,因为偏移值实际上会将单词从其默认位置移动(由 确定WrapPanel
,因此它们可能会根据WrapPanel
自身的大小而变化) .