我需要知道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>
ListBox
绑定到ObservableCollection
。
我在滚动ListBox
时遇到问题 - 如果RichTextBox
的高度大于ListBox
的高度,则用户无法滚动到RichTextBox
的底部{1}}。 ListBox
将跳转到列表中的下一个项目。滚动条滑块的高度也会改变。这是因为RichTextBox
的实际高度仅在实际渲染时计算。当它离开屏幕时,高度会恢复到较小的值(我认为代码假定文本可以全部放在一行而不必包裹)。
我将这些问题跟踪到ListBox
使用VirtualisingStackPanel
来绘制项目。当我用一个简单的StackPanel
替换它时,这些问题就消失了。
然后创建了我现在遇到的问题,即ListBox
在初始加载时滚动到列表的底部。 Loaded
上的LayoutUpdated
和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;
}
}
这也太早了。该事件被触发后, 后会显示该列表,并导致ListBox
滚动到底部。
答案 0 :(得分:0)
尝试滚动Loaded处理程序,但Dispatcher稍微延迟一下。像这样的东西
void OnLoaded(...)
{
Dispatcher.BeginInvoke(() => {/*Scroll your ListBox here*/});
}
这可能有所帮助。
答案 1 :(得分: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();
}
如果有人知道更好的方法,请立即发布您的答案。
答案 2 :(得分: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属性。