我想設計一個控件,允許用戶滾動上下滾動向上或向下列表的類似感覺的數字範圍(例如0-2000)。最簡單的方法來模擬無限滾動選擇器與UWP
我試過在Flyout
裏面使用ListView
或GridView
這個,但是加載幾千個項目實在太慢了。
現在我想最好的方式可能是簡單地模擬列表滾動而不實際有任何項目(即無限滾動選擇器)。任何有關使用什麼控制作爲實現這樣一個無限選擇器的基礎的建議?
我想設計一個控件,允許用戶滾動上下滾動向上或向下列表的類似感覺的數字範圍(例如0-2000)。最簡單的方法來模擬無限滾動選擇器與UWP
我試過在Flyout
裏面使用ListView
或GridView
這個,但是加載幾千個項目實在太慢了。
現在我想最好的方式可能是簡單地模擬列表滾動而不實際有任何項目(即無限滾動選擇器)。任何有關使用什麼控制作爲實現這樣一個無限選擇器的基礎的建議?
我試圖在Flyout中使用ListView或GridView來實現此目的,但是它僅僅爲加載幾千個項目太慢。
根據您的要求,您不必一次創建所有項目。 您可以通過執行ISupportIncrementalLoading
接口按需要加載其餘項目。它允許輕鬆地創建一個集合,在用戶即將到達用戶界面上可用項目的末尾時,以增量方式加載數據。使用它,我們可以獲得一個快速的流體滾動,同時加載一大組記錄。
public class ItemToShow : ObservableCollection<string>, ISupportIncrementalLoading
{
public int lastItem = 1;
public bool HasMoreItems
{
get
{
if (lastItem == 2000) return false;
else return true;
}
}
public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
{
var progressBar = ((Window.Current.Content as Frame).Content as MainPage).MyProgressBar;
CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
return Task.Run<LoadMoreItemsResult>(() =>
{
coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
{
progressBar.IsIndeterminate = true;
progressBar.Visibility = Visibility.Visible;
});
List<string> items = new List<string>();
for (var i = 0; i < count; i++)
{
items.Add(string.Format("Items{0}", lastItem));
lastItem++;
if (lastItem == 2000)
break;
}
coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,() =>
{
foreach (string item in items)
{
this.Add(item);
progressBar.Visibility = Visibility.Collapsed;
progressBar.IsHoldingEnabled = false;
}
});
return new LoadMoreItemsResult() { Count = count };
}).AsAsyncOperation<LoadMoreItemsResult>();
}
}
用法
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView
x:Name="ListViewMain"
Margin="0,100,0,0"
Padding="100,0,0,10">
<ListView.Resources>
<DataTemplate x:Key="DataTemplateListViewMain">
<Grid
Width="100"
Height="100"
Background="LightGray">
<TextBlock
VerticalAlignment="Center"
FontSize="18"
Text="{Binding}"
TextAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.Resources>
<ListView.ItemTemplate>
<StaticResource ResourceKey="DataTemplateListViewMain" />
</ListView.ItemTemplate>
</ListView>
<ProgressBar
x:Name="MyProgressBar"
Height="10"
Margin="0,5,0,0"
VerticalAlignment="Top"
x:FieldModifier="public"
Visibility="Collapsed" />
</Grid>
MainPage.xaml.cs中
private void Page_Loaded(object sender, RoutedEventArgs e)
{
ListViewMain.ItemsSource = new ItemToShow();
}
這裏環繞虛擬滾輪。它只保留5個項目,所以你可以添加很多。爲了進行選擇,您可以在Item上添加一個事件。
public sealed partial class MainPage
{
private static int Count = 20;
private static float ItemSize = 128;
private Visual _spawnerVisual;
private readonly List<ItemModel> _items = new List<ItemModel>();
private readonly List<Item> _selectedItems = new List<Item>();
private int _index;
private static readonly Random Random = new Random();
public MainPage()
{
InitializeComponent();
Loaded += MainPage_Loaded;
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
PopulateItems();
SetInitialItems();
}
private void PopulateItems()
{
for (int i = 0; i < Count; i++)
{
_items.Add(new ItemModel());
}
}
private void SetInitialItems()
{
_index = -5;
for (int i = 0; i < 5; i++)
{
KillAtTop(true);
}
_spawnerVisual = ElementCompositionPreview.GetElementVisual(Spawner);
}
private void KillAtTop(bool atTop)
{
if (atTop)
{
if (_selectedItems.Count > 4)
{
_selectedItems.RemoveAt(0);
Spawner.Children.RemoveAt(0);
}
var index = GetIndex(_index + 3);
var item = new Item
{
Id = index,
BackColor = Color.FromArgb(255, (byte)Random.Next(0, 255), (byte)Random.Next(0, 255), (byte)Random.Next(0, 255)),
ItemSize = ItemSize,
ItemModel = _items[index],
OffsetY = (_index + 6) * ItemSize
};
_selectedItems.Add(item);
Spawner.Children.Add(item);
_index++;
}
else
{
if (_selectedItems.Count > 4)
{
_selectedItems.RemoveAt(_selectedItems.Count - 1);
Spawner.Children.RemoveAt(Spawner.Children.Count - 1);
}
var index = GetIndex(_index - 3);
var item = new Item
{
Id = index,
BackColor = Color.FromArgb(255, (byte)Random.Next(0, 255), (byte)Random.Next(0, 255), (byte)Random.Next(0, 255)),
ItemSize = ItemSize,
ItemModel = _items[index],
OffsetY = _index * ItemSize
};
_selectedItems.Insert(0, item);
Spawner.Children.Insert(0, item);
_index--;
}
}
private int GetIndex(int index)
{
index = index % _items.Count;
if (index > _items.Count - 1) return index - _items.Count;
if (index < 0) return _items.Count + index;
return index;
}
private void Slider_OnSetDelta(float deltaY)
{
SetPosition(deltaY);
}
public void SetPosition(float offsetY)
{
_spawnerVisual.Offset += new Vector3(0, offsetY/10, 0);
if (_spawnerVisual.Offset.Y > -ItemSize * _index + ItemSize)
{
KillAtTop(false);
}
if (_spawnerVisual.Offset.Y < -ItemSize * _index)
{
KillAtTop(true);
}
}
}
只需添加您的ItemControl並調用SetPosition進行滾動。 應該是這樣的:
非常有趣的方法!雖然希望看到GitHub回購。 :P –
這是之前,我真的希望它會工作,我從來沒有見過一個非常有趣的方法。不幸的是,它仍然懸掛着我的「Flyout」。通過設置斷點,我發現'LoadMoreItemsAsync'方法在快速連續調用中首先使用'count = 1',然後是3,12,48,192等,直到整個序列沒有被展開,甚至沒有我嘗試滾動列表。 – glopes
更有趣的是,如果我將'ListView'放在'Flyout'之外,這種奇怪的行爲就不會發生,所以看起來渴望的展開來自'Flyout'類。 – glopes
是的,我沒有在Flyout中放置listview。我認爲在Flyout中渲染太多物品是非理性的設計。 –