2012-07-02 22 views
7

Tôi cần biết khi nào ListBox đã hoàn tất hiển thị lần đầu tiên để tôi có thể cuộn hình ảnh đó lên trên cùng để hiển thị cho người dùng mục đầu tiên trong danh sách.Làm cách nào để biết khi nào một ListBox đã hoàn tất hiển thị trong Silverlight?

Tôi có một ListBox sử dụng RichTextBox trong nó 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> 

Các ListBox là ràng buộc để một ObservableCollection.

Tôi gặp sự cố khi cuộn ListBox - nếu chiều cao của RichTextBox lớn hơn số ListBox, người dùng không thể cuộn xuống dưới cùng của RichTextBox. ListBox sẽ chuyển sang mục tiếp theo trong danh sách. Chiều cao của thanh trượt của thanh cuộn cũng sẽ thay đổi. Điều này là do chiều cao thực tế của RichTextBox chỉ được tính khi nó thực sự được hiển thị. Khi nó tắt màn hình, chiều cao sẽ chuyển về giá trị nhỏ hơn (tôi nghĩ rằng mã giả định rằng tất cả văn bản có thể vừa với một dòng duy nhất thay vì phải được bao bọc).

Tôi đã theo dõi các sự cố này xuống mức sử dụng ListBox sử dụng số VirtualisingStackPanel để vẽ các mục. Khi tôi thay thế bằng một số StackPanel những vấn đề đó đã biến mất.

Điều này sau đó đã tạo ra sự cố hiện tại của tôi là di chuyển ListBox xuống cuối danh sách khi tải ban đầu. Các sự kiện LoadedLayoutUpdated trên ListBox xảy ra trước khi dữ liệu được tải. Tôi cố gắng nghe ra cho sự kiện PropertyChanged trên mô hình xem khi ObservableCollection được khởi tạo:

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

này bắn quá sớm là tốt. Danh sách được hiển thị sau sự kiện này được kích hoạt và gây ra ListBox để cuộn xuống dưới cùng.

Trả lời

0

Cuối cùng tôi đã phải sử dụng một 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(); 
} 

Nếu có ai biết một cách tốt hơn xin vui lòng gửi câu trả lời bạn ngay bây giờ.

0

Cố gắng cuộn vào trong Trình xử lý được tải, nhưng trì hoãn trình xử lý một chút theo Người điều phối. Một cái gì đó như thế

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

Nó có thể hữu ích.

+0

Hmm. Tôi cảnh giác với những thứ như thế này - đặc biệt là vì có thể có nhiều thứ trong danh sách - nhưng tôi sẽ cho nó đi. – ChrisF

+0

Vì quá trình kết xuất diễn ra trong chuỗi giao diện người dùng và Dispatcher.BeginInvoke đẩy hoạt động cuộn vào hàng đợi của chuỗi giao diện người dùng - nó thực sự không quan trọng danh sách của bạn lớn đến cỡ nào. Việc di chuyển phải được thực hiện sau khi các chỉ dẫn luồng giao diện người dùng hiện tại khác được thực hiện. Tất nhiên nếu bộ sưu tập của bạn (hoặc các phần khác của điều khiển/mẫu) được tạo không đồng bộ - nó sẽ không hoạt động.Nhưng nó là một trường hợp khác .. Thông thường cho các kịch bản đơn giản nó hoạt động. – Kreol

+0

Điểm tốt ở đó - mặc dù danh sách được phổ biến không đồng bộ .... – ChrisF

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 
    } 

sau đó sử dụng trong XAML như

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

trên một số lệnh bạn sẽ có thể kiểm soát và thiết lập thuộc tính của mô hình quan điểm của bạn SelectedItemFromModel.