2010-12-21 18 views
5

que tienen un control de usuario que tiene una altura de 100 Canvas y anchura 1920.WPF ActualWidth es cero

En la carga del control, voy a una fuente externa, descargar un archivo de texto y añadir a TextBlock s el lienzo. Entonces quiero crear un efecto de desplazamiento de marquesina que debería funcionar bien, excepto después de agregar el TextBlock al Canvas, necesito obtener su ancho para fines de cálculo, pero la propiedad ActualWidth siempre es cero.

Aquí hay un código:

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 no es visible y no está cargado, por lo que no tiene una propiedad ActualWidth. He resuelto un problema similar con Itemscontrol, pero no estoy seguro de Canvas. Pruebe eventos como LayoutUpdated, SizeChanged, etc. – vorrtex

Respuesta

3

Si desea seguir con su llamada de despachador - establezca la prioridad en cargado, entonces se llamará a la misma hora que el evento cargado y debe tener un valor. Hay una sobrecarga en BeginInvoke que también tiene prioridad.

+0

Sí que trabajó muchas gracias! – Mark

1

Cualquier Control 's ActualHeight o ActualWidth siempre será cero antes de que sean Loaded>Measured>Arranged>Rendered.

En su caso, le recomiendo usar Loaded o SizeChanged evento de ese TextBlock a su favor.

+0

hay muchos bloques de texto sin embargo, tendría que suscribirme al evento Loaded del último añadido que parece un poco hackeo ¿no crees? – Mark

+0

¡Supongo que tienes razón! A menos que agregue estos controles 'TextBlock' en un' StackPanel' con orientación 'Horizontal' y recorra ese panel. En ese caso, tendría que tratar con los eventos de 'Panel' solamente. – decyclone

0

¿Hay alguna razón en particular para usar Canvas para el diseño del TextBlock s? Si no es así, será mejor que utilice un StackPanel con orientación horizontal, se encargará de las matemáticas de diseño para usted.

+0

estoy haciendo un efecto de marquesina que significa que cada elemento realmente tiene que ser individual y una posición absoluta en el lienzo – Mark

+0

ahora tiene sentido =) – xenry

4

Siempre se puede adjuntar un delgate a la PropertyMetatdata/OnValueChanged y cuando ActualHeight/ActualWidth cambia de 0 a algo, ajustar su desplazamiento, ActualWidth/ActualHeight tendrá un valor una vez que su dictó al menos una vez:

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

que es un truco genial que podría ser útil en algún momento :) –