2010-12-21 5 views
5

ich ein Benutzersteuer haben, die eine Canvas der Höhe hat 100 und Breite 1920.WPF Actual Null

Bei der Belastung der Steuer, ich auf eine externe Quelle gehen, laden Sie eine Textdatei und fügen Sie TextBlock s die Leinwand. Dann möchte ich einen Laufschrift Scroll-Effekt erstellen, der gut funktionieren sollte, außer nachdem ich die TextBlock s zu der Canvas s hinzufügen, muss ich ihre Breite für Berechnungszwecke erhalten, aber die ActualWidth Eigenschaft ist immer Null. Hier

ist ein Code:

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- nicht sichtbar ist und ist nicht geladen, also hat es keine Eigenschaft ActualWidth. Ich habe ein ähnliches Problem mit Itemscontrol gelöst, aber ich bin mir nicht sicher über Canvas. Probieren Sie Ereignisse wie LayoutUpdated, SizeChanged usw. aus. – vorrtex

Antwort

3

Wenn Sie bei Ihrem Dispatcher-Anruf bleiben möchten - setzen Sie die Priorität auf geladen, dann wird es gleichzeitig mit dem geladenen Ereignis aufgerufen und Sie sollten einen Wert haben. Es gibt eine Überladung bei BeginInvoke, die auch eine Priorität hat.

+0

Ja, das hat sehr gut funktioniert! – Mark

1

Alle Control ‚s ActualHeight oder ActualWidth wird immer Null sein, bevor sie Loaded sind>Measured>Arranged>Rendered.

In Ihrem Fall empfehle ich Loaded oder SizeChanged Ereignis dieses TextBlock zu Ihrem Vorteil.

+0

Es gibt viele viele Textblöcke, aber ich würde das Loaded-Event des letzten hinzufügen müssen, das wie ein bisschen wie ein Hack aussieht, denkst du nicht? – Mark

+0

Ich denke du hast Recht! Es sei denn, Sie fügen diese 'TextBlock'-Steuerelemente in einem' StackPanel' mit horizontaler Ausrichtung hinzu und scrollen diesen Bereich. In diesem Fall müssten Sie nur mit den Ereignissen dieses "Panels" arbeiten. – decyclone

0

Gibt es einen bestimmten Grund für die Verwendung Canvas für das Layout der TextBlock s? Wenn nicht, verwenden Sie besser eine StackPanel mit horizontaler Ausrichtung, damit wird die Layout-Mathematik für Sie erledigt.

+0

Ich mache einen Scroll-Laufschrift-Effekt, was bedeutet, dass jeder Artikel wirklich individuell und absolut auf der Leinwand positioniert werden muss – Mark

+0

macht es jetzt Sinn =) – xenry

4

Man konnte immer eine delgate an die PropertyMetatdata/OnValueChanged befestigen und wenn ActualHeight/ActualWidth von 0 auf etwas, Ihr Scrollen einstellen, ActualWidth/ActualHeight einen Wert haben, wenn sie mindestens einmal gemacht:

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

das ist ein cooler Trick, der irgendwann nützlich sein könnte :) –