WPF ActualWidth равен нулю - PullRequest
       11

WPF ActualWidth равен нулю

5 голосов
/ 21 декабря 2010

У меня есть пользовательский элемент управления, который имеет Canvas высоты 100 и ширины 1920.

При загрузке элемента управления я захожу во внешний источник, загружаю текстовый файл и добавляю TextBlockс холстом.Затем я хочу создать эффект прокрутки выделения, который должен работать просто отлично, за исключением того, что после добавления 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;
        }
    }));
}

Ответы [ 4 ]

5 голосов
/ 21 декабря 2010

Вы всегда можете прикрепить delgate к PropertyMetatdata/OnValueChanged, и когда ActualHeight/ActualWidth изменится с 0 на что-то, отрегулируйте прокрутку, 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
   ...
}
3 голосов
/ 21 декабря 2010

Если вы хотите придерживаться вызова диспетчера - установите приоритет для загруженного, тогда он будет вызван в то же время, что и загруженное событие, и у вас должно быть значение.В BeginInvoke имеется перегрузка, которая также имеет приоритет.

1 голос
/ 21 декабря 2010

Любой Control * ActualHeight или ActualWidth всегда будет равен нулю, прежде чем они Loaded> Measured> Arranged> Rendered.

В вашем случае я рекомендую использовать Loaded или SizeChanged событие этого TextBlock в ваших интересах.

0 голосов
/ 21 декабря 2010

Есть ли какая-либо конкретная причина для использования Canvas для макета TextBlock s?Если нет, то вам лучше использовать StackPanel с горизонтальной ориентацией, он будет обрабатывать математику для вас.

...