在我看來,我有一個ListBox
,綁定到一個動態增長的集合。我希望滾動位置可以追蹤最後添加的項目(附加到列表底部)。我如何通過Caliburn.Micro實現這一目標?如何使用caliburn.micro設置視圖模型的滾動位置?
回答
另一種方法是使用事件聚合器將消息發佈到視圖。
喜歡的東西:
Aggregator.Publish(ItemAddedMessage<SomeItemType>(itemThatWasJustAdded));
,並在視圖:
public class SomeView : IHandle<ItemAddedMessage<SomeItemType>>
{
public void Handle(ItemAddedMessage<SomeItemType> message)
{
// Implement view specific behaviour here
}
}
這取決於你的需求是什麼,但至少再視圖負責顯示的擔憂,你仍然可以測試VM
你也可以只實現代碼僅在視圖 - 因爲它似乎是一個視圖關注(例如,使用列表框提供的事件)
一種行爲也會很有用,但也許會對您的類型有一些幫助 - 例如一個通用行爲SeekAddedItemBehaviour
,它鉤住列表框事件以查找最後一個項目。不知道,如果列表框暴露所需的事件,但值得一看
編輯:
確定這可能工作句號 - 你應該能夠只重視這種行爲的列表框和應採取的護理休息:
public class ListBoxSeekLastItemBehaviour : System.Windows.Interactivity.Behavior<ListBox>
{
private static readonly DependencyProperty ItemsSourceWatcherProperty = DependencyProperty.Register("ItemsSourceWatcher", typeof(object), typeof(ListBoxSeekLastItemBehaviour), new PropertyMetadata(null, OnItemsSourceWatcherPropertyChanged));
private ListBox _listBox = null;
private static void OnItemsSourceWatcherPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBoxSeekLastItemBehaviour source = d as ListBoxSeekLastItemBehaviour;
if (source != null)
source.OnItemsSourceWatcherPropertyChanged();
}
private void OnItemsSourceWatcherPropertyChanged()
{
// The itemssource has changed, check if it raises collection changed notifications
if (_listBox.ItemsSource is INotifyCollectionChanged)
{
// if it does, hook the CollectionChanged event so we can respond to items being added
(_listBox.ItemsSource as INotifyCollectionChanged).CollectionChanged += new NotifyCollectionChangedEventHandler(ListBoxSeekLastItemBehaviour_CollectionChanged);
}
}
void ListBoxSeekLastItemBehaviour_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count > 0)
{
// If an item was added seek it
ScrollIntoView(e.NewItems[0]);
}
}
protected override void OnAttached()
{
base.OnAttached();
// We've been attached - get the associated listbox
var box = this.AssociatedObject as ListBox;
if (box != null)
{
// Hold a ref
_listBox = box;
// Set a binding to watch for property changes
System.Windows.Data.Binding binding = new System.Windows.Data.Binding("ItemsSource") { Source = _listBox; }
// EDIT: Potential bugfix - you probably want to check the itemssource here just
// in case the behaviour is applied after the original ItemsSource binding has been evaluated - otherwise you might miss the change
OnItemsSourceWatcherPropertyChanged();
}
}
private void ScrollIntoView(object target)
{
// Set selected item and try and scroll it into view
_listBox.SelectedItem = target;
_listBox.ScrollIntoView(target);
}
}
你可能想整理一下了一下,也確保了CollectionChanged
事件處理程序的ItemsSource
更改時刪除。你
可能還需要調用它SeekLastAddedItemBehaviour
或SeekLastAddedItemBehavior
- 我傾向於保持美國的拼寫,因爲它微軟的拼寫匹配。我認爲SeekLastItem
聽起來像它會滾動到列表中的最後一個項目,而不是最後添加的項目
您可以使用GetView()引用視圖模型中的視圖。這也加上了觀點和觀點模型。
var myView = GetView() as MyView;
myView.MyListBox.DoStuff
另一種選擇是創建一個行爲。 This是如何使用行爲從視圖模型中擴展TreeView
的示例。這同樣適用於ListBox
。
讓ViewModel操縱視圖並不總是一個好主意 - 您將如何區分「ViewModel」的單元測試? *最好的答案是創建一個Derek指出的行爲。 - 行爲在View中保留,這將顯示問題保留在正確的層次上。 – EtherDragon 2013-03-07 22:45:47
我同意,這就是爲什麼我通常使用行爲或實現IResult,但仍然從vm引用視圖是一個選項。這是一種方便,快速和骯髒的方式來做一個概念證明,以後可以轉移到更多的解耦選項。 – 2013-03-08 17:51:59
我在之前的評論中提到了IResult,在這個特殊情況下它不起作用,所以我沒有將它包含在答案中。由於傳遞的ActionExecutionContext,IResult在某些情況下非常方便。 – 2013-03-08 17:55:55
實際上,有一個更簡單的方法來實現這一點,沒有任何上述。然後
namespace Extensions.Examples {
public class ScrollingListBox : ListBox
{
protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
int newItemCount = e.NewItems.Count;
if (newItemCount > 0)
this.ScrollIntoView(e.NewItems[newItemCount - 1]);
base.OnItemsChanged(e);
}
}
}
}
在XAML中,聲明你的擴展類的位置,因爲這樣:
只是下面的擴展您的列表框
xmlns:Extensions="clr-namespace:Extensions.Examples"
當您創建列表框,而不是使用
<Listbox></Listbox>
只需使用您的擴展類
<Extensions:ScrollingListBox></Extensions:ScrollingListBox>
- 1. expandablelist視圖滾動位置
- 2. Uitextview滾動視圖位置
- 3. 如何設置UIScrollView的滾動位置?
- 4. 如何設置滾動位置長PreferenceScreen
- 5. 滾動窗格設置滾動位置
- 6. 設置滾動位置
- 7. 如何設置div內滾動div的滾動位置?
- 8. 如何在滾動視圖中保存滾動位置?
- 9. 如何將滾動條/視圖置於頂部位置?
- 10. 如何獲取上一個滾動視圖位置,滾動視圖
- 11. Backbone.js的設置使用模型視圖EL id屬性動態
- 12. 的Android如何設置滾動型
- 13. 如何使用滾動條重置滾動條內的滾動條位置?
- 14. 在滾動時跟蹤滾動視圖中圖像的位置
- 15. 如何設置從jQuery的視圖模型值MVC Rozor視圖
- 16. 如何設置此數據以使用視圖和模型
- 17. 如何設置圖表的滾動條比例視圖位置到最近使用c增加值#
- 18. 如何設置一個視圖不滾動與Java滾動視圖
- 19. Recycler視圖滾動到特定位置
- 20. 如何使用ActionScript3.0的設置在圖像的動態位置?
- 21. Caliburn.Micro,如何訪問從視圖內使用的實際視圖模型
- 22. 如何使用位置:絕對滾動
- 23. 如何在使用addView時設置視圖位置
- 24. 設置滾動條的位置
- 25. 設置一個滾動條的位置
- 26. 設置列表框的滾動位置
- 27. 設置ListBox的滾動條位置
- 28. 根據滾動設置div的位置
- 29. 我如何設置水平滾動視圖的圖像對齊
- 30. 當在子視圖位置選擇滾動視圖子視圖滾動
只要看一下,它似乎並不像'ListBox'知道'ItemsSource'的變化(在Silverlight中),所以它可能無法寫出一個通用的行爲。有一個'ScrollIntoView'方法需要一個對象 - 設置SelectedItem並調用ScrollIntoView可能會做到這一點,但在不知道'ItemsSource'變化的時候,鉤住列表更改事件會很困難! – Charleh 2013-03-08 14:15:47
那麼有人設法通過創建一個綁定來觀察屬性的變化 - 我堅持在那裏的行爲的實現。它應該工作,但我沒有測試它。 – Charleh 2013-03-08 14:28:27