要回答你的問題:
Dispatcher.BeginInvoke()
在分派器的「等待作業」隊列中排隊操作。這使其能夠處理第一個UI元素的添加,並在繼續執行代碼之前運行Layout
和Render
遍。
因此,當你的代碼運行時,第一個TextBlock的大小已經被計算出來了,你可以得到它。
同樣,我不知道你在試圖做什麼,但是在代碼中創建UI元素通常是設計不佳的標誌。 WPF不是winforms,而WPF的方式與在winforms中做任何事情所需的可怕黑客完全不同。
編輯:
這是使用WrapPanel
和一些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");
}
}
}
PropertyChangedBase:
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
的大小本身)。
老兄,我不知道你在做什麼,但是你的代碼太可怕了。你爲什麼要在代碼中創建UI元素?這就是XAML的用途。 –
單詞將在運行時讀入。我無法將它們硬編碼到XAML中。 – Sabuncu
然後創建一個'ItemsControl'或其他東西。您也可以將它們放在一個TextBlock中。否則使用'WrapPanel'或其他東西。 Canvas不是Text的正確容器。 WPF不是winforms。你的代碼仍然很糟糕。如果不同'TextBlock'之間的屬性相同,則使用XAML定義的樣式。發佈你需要的截圖,我可以告訴你在WPF中實現它的正確方法。 –