2010-12-21 36 views
5

我有一個具有高度100的Canvas和寬度1920WPF ActualWidth的是零

在控制的負荷,我去到外部源的用戶控件,下載一個文本文件,並添加TextBlock s到帆布。然後我想創建一個字幕滾動效果,這應該工作得很好,除了我將TextBlock s添加到Canvas之後,我需要獲取它們的寬度以用於計算目的,但ActualWidth屬性始終爲零。

下面是一些代碼:

private readonly LinkedList<TextBlock> textBlocks = new LinkedList<TextBlock>(); 

public LocalNewsControl() 
{ 
    Loaded += LocalNewsControlLoaded; 
} 

private void LocalNewsControlLoaded(object sender, RoutedEventArgs e) 
{ 
    LoadDataContext(); 
} 

private void LoadDataContext() 
{ 
    DataContext = new NewsItemsViewModel((exception) => LoadNewsItems()); 
} 

private void LoadNewsItems() 
{ 
    var viewModel = (NewsItemsViewModel)DataContext; 

    NewsCanvas.Children.Clear(); 
    textBlocks.Clear(); 

    foreach (var newsViewModel in viewModel.NewsItems) 
    { 
     var tb = new TextBlock 
     { 
      Text = newsViewModel.Headline, 
      FontSize = 28, 
      FontWeight = FontWeights.Normal, 
      Foreground = Brushes.Black 
     }; 

     NewsCanvas.Children.Add(tb); 

     Canvas.SetTop(tb, 20); 
     Canvas.SetLeft(tb, -999); 

     textBlocks.AddLast(tb); 
    } 

    Dispatcher.BeginInvoke(new Action(() => 
    { 
     var node = textBlocks.First; 

     while (node != null) 
     { 
      if (node.Previous != null) 
      { 
       //THIS IS WHERE ActualWidth is always ZERO 
       var left = Canvas.GetLeft(node.Previous.Value) + node.Previous.Value.ActualWidth + Gap; 
       Canvas.SetLeft(node.Value, left); 
      } 
      else 
       Canvas.SetLeft(node.Value, NewsCanvas.Width + Gap); 

      node = node.Next; 
     } 
    })); 
} 
+1

TextBlock中是不可見的,未加載,因此它沒有屬性ActualWidth。我已經解決了與ItemsControl類似的問題,但我不確定Canvas。嘗試像LayoutUpdated,SizeChanged等事件。 – vorrtex 2010-12-21 11:09:07

回答

3

如果你想堅持你的調度器調用 - 設置優先級加載,那麼它將被稱爲與加載的事件相同的時間,你應該有一個值。 BeginInvoke上還有一個重載也會佔用優先級。

+0

是的,工作非常感謝! – Mark 2010-12-21 12:08:26

1

不限ControlActualHeightActualWidth將始終爲零它們Loaded>Measured>Arranged>Rendered之前。

在你的情況下,我建議使用LoadedSizeChanged事件TextBlock你的優勢。

+0

雖然有很多很多的文本塊,但我必須訂閱最後一個加載的事件,這似乎有點像黑客,你不覺得? – Mark 2010-12-21 10:58:23

+0

我想你是對的!除非在'Horizo​​ntalPanel'中添加這些'TextBlock'控件並使用'Horizo​​ntal'方向並滾動該面板。在這種情況下,你只能處理那個'Panel'的事件。 – decyclone 2010-12-21 11:02:09

0

使用Canvas作爲TextBlock的佈局有什麼特別的理由嗎?如果沒有,你最好使用水平方向的StackPanel,它會爲你處理佈局數學。

+0

即時通訊做滾動字幕效果,這意味着每個項目真的需要個人和絕對放置在畫布上 – Mark 2010-12-21 12:09:14

+0

它現在有道理=) – xenry 2010-12-21 12:26:36

4

你可以總是delgate連接到PropertyMetatdata/OnValueChanged,當從0 ActualHeight/ActualWidth變化的東西,調整滾動,ActualWidth/ActualHeight將有一個價值一旦其呈現至少一次:

LocalNewsControl() 
{ 
    var descriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, typeof(TextBlock)); 
    if (descriptor != null) 
     descriptor.AddValueChanged(myTextBlock, ActualWidth_ValueChanged); 
} 

private void ActualWidth_ValueChanged(object a_sender, EventArgs a_e) 
{ 
    //Modify you scroll things here 
    ... 
} 
+0

這是一個很酷的把戲,可能會在某些方面:) – 2010-12-21 12:29:11