7

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

我有一个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>

ListBox绑定到ObservableCollection一个.

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

我将这些问题追溯到ListBox使用 aVirtualisingStackPanel来绘制项目。当我用简单的替换它时,StackPanel这些问题就消失了。

然后这产生了我现在遇到的问题,即ListBox在初始加载时滚动到列表底部。和事件Loaded发生在数据加载之前。我尝试在初始化时监听视图模型上的事件:LayoutUpdatedListBoxPropertyChangedObservableCollection

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

这也太早了。该列表在此事件被触发并导致滚动到底部后呈现。ListBox

4

3 回答 3

0

尝试在 Loaded 处理程序上滚动,但通过 Dispatcher 将其延迟一点。类似的东西

void OnLoaded(...)
{
   Dispatcher.BeginInvoke(() => {/*Scroll your ListBox here*/});
}

它可以提供帮助。

于 2012-07-06T21:39:33.090 回答
0

最后我不得不使用一个kludge:

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();
}

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

于 2012-07-30T08:15:20.880 回答
0
public class AutoScrollBehavior : Behavior<ListBox>
    {
        #region Properties

        public object ItemToScroll
        {
            get { return GetValue(ItemToScrollProperty); }
            set { SetValue(ItemToScrollProperty, value); }
        }

        public static readonly DependencyProperty ItemToScrollProperty = DependencyProperty.Register("ItemToScroll", typeof(object), typeof(AutoScrollBehavior), new PropertyMetadata(ItemToScrollPropertyChanged));

        private static void ItemToScrollPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ListBox lb = ((AutoScrollBehavior)d).AssociatedObject;
            lb.UpdateLayout();
            ((AutoScrollBehavior)d).AssociatedObject.ScrollIntoView(e.NewValue);
        }
        #endregion
    }

然后在 XAML 中用作

<ListBox SelectedItem="{Binding SelectedItemFromModel, Mode=TwoWay}">
<i:Interaction.Behaviors>
                                                                <Behaviors:AutoScrollBehavior ItemToScroll="{Binding SelectedItemFromModel}"/>
                                                            </i:Interaction.Behaviors>
</ListBox>

在某些命令上,您应该能够控制和设置视图模型的 SelectedItemFromModel 属性。

于 2012-11-15T16:07:06.427 回答