如何知道ListBox何时在Silverlight中完成渲染?

Chr*_*isF 7 silverlight rendering listbox

我需要知道ListBox第一次完成渲染的时间,以便我可以将其滚动到顶部以向用户显示列表中的第一个项目.

我有一个ListBox用于RichTextBox它的DataTemplate:

<DataTemplate x:Key="HelpTextTemplate">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        ...
        <ContentControl>
            ...
            <RichTextBox x:Name="HelpTextContent" Grid.Row="1"
                         Tag="{Binding Path=HelpObject.Text, Mode=TwoWay}"
                         TextWrapping="Wrap"
                         HorizontalAlignment="Stretch"
                         Margin="0,0,20,0"
                         Loaded="RichTextBox_Loaded"
                         ContentChanged="RichTextBox_ContentChanged"
                         SelectionChanged="RichTextBox_SelectionChanged"/>
            ...
        </ContentControl>
        ...
    </Grid>
</DataTemplate>
Run Code Online (Sandbox Code Playgroud)

ListBox是必然的ObservableCollection.

滚动时我遇到了问题ListBox- 如果高度RichTextBox大于ListBox用户无法滚动到底部RichTextBox.该ListBox会跳转到下一个项目在列表中.滚动条滑块的高度也会改变.这是因为它的实际高度RichTextBox仅在实际渲染时计算.当它离开屏幕时,高度恢复到较小的值(我认为代码假定文本可以全部放在一行而不是必须被包裹).

我将这些问题追踪到ListBox使用a VirtualisingStackPanel来绘制物品.当我用简单的替换它时,StackPanel那些问题就消失了.

这就产生了我现在ListBox遇到的问题,即在初始加载时滚动到列表的底部.在LoadedLayoutUpdated事件上ListBox的数据已经被加载之前发生.初始化PropertyChanged时,我尝试在视图模型上监听事件ObservableCollection:

void editViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "ListDataSource":
            // Try to scroll to the top of the ListBox
            break;
    }
}
Run Code Online (Sandbox Code Playgroud)

这太火了.触发此事件后将呈现该列表,并使其ListBox滚动到底部.

Chr*_*isF 0

最后我不得不使用一个拼凑:

private System.Threading.Timer timer;
void editViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "ListDataSource":
            TimerCallback callback = TimerResult;
            timer = new Timer(callback, null, 750, 0);
            break;
    }
}

private void TimerResult(Object stateInfo)
{
    Dispatcher.BeginInvoke(() =>
    {
        if (this.ItemsList.Items.Count > 0)
        {
            this.ItemsList.UpdateLayout();
            this.ItemsList.SelectedIndex = 0;
            this.ItemsList.ScrollIntoView(this.ItemsList.Items[0]);
        }
    });

    timer.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

如果有人知道更好的方法,请立即发布您的答案。