[英]How can I access a resource when it's declared as a Class in C# back end?
[英]Is there any way that I can speed up the adding of new elements to a page when using the C# back end?
我有可行的代码,但我注意到创建页面元素的速度相当慢。
这是我到目前为止所拥有的。 请注意,我没有立即添加所有内容,因为我发现创建页面时速度更慢。
public void CreateSwitchSection(bool? selected)
{
Application.Current.Resources.TryGetValue("FrameBorder", out object frameBorder);
var st = new StackLayout { Orientation = StackOrientation.Vertical, Spacing = 0 };
st.Children.Add(AddSwitchRows(selected, App.cardSetWithWordCount.Take(20)));
st.Children.Add(AddSwitchRows(selected, App.cardSetWithWordCount.Skip(20).Take(20)));
st.Children.Add(AddSwitchRows(selected, App.cardSetWithWordCount.Skip(40).Take(20)));
st.Children.Add(AddSwitchRows(selected, App.cardSetWithWordCount.Skip(60).Take(20)));
st.Children.Add(AddSwitchRows(selected, App.cardSetWithWordCount.Skip(80).Take(20)));
var fr = new Frame { Style = (Style)frameBorder };
var fs = new FrameStack { };
var ht = new HeaderTemplate()
{
Text = "CHOOSE CARD SETS FOR THE DECK"
};
fs.Children.Add(ht);
fs.Children.Add(st);
fs.Children.Add(new LineTemplate());
fr.Content = fs;
details.Children.Clear();
details.Children.Add(fr);
}
private StackLayout AddSwitchRows(bool? selected, IEnumerable<CardSetWithWordCount> data)
{
var stack = new StackLayout
{
Orientation = StackOrientation.Vertical,
Spacing = 0
};
foreach (var x in data)
{
var cell = new BadgeGridTemplate
{
BindingContext = x,
Text = x.Name,
State = selected == true ? "E" : "D",
Message = x.TotalWordCount.ToString(),
TapCommand = (Command)vm.SelectCardSetCmd,
RowId = x.Id,
Separator = true
};
stack.Children.Add(cell);
}
return stack;
}
这里参考的是我编写的BadgeGridTemplate:
<?xml version="1.0" encoding="UTF-8"?>
<t:BaseGridTemplate xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:t="clr-namespace:Japanese.Templates"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=Japanese"
xmlns:b="clr-namespace:Behaviors;assembly=Behaviors"
xmlns:converters="clr-namespace:Japanese.Converters;assembly=Japanese"
x:Class="Japanese.Templates.BadgeGridTemplate"
x:Name="this"
HeightRequest="{DynamicResource GridHeight}" Margin="0"
Orientation="Vertical" Spacing="0">
<BoxView HeightRequest="1" HorizontalOptions="FillAndExpand" IsVisible="{Binding Separator, Source={x:Reference this}}" BackgroundColor="{DynamicResource LineColor}" Margin="0" />
<Grid Padding="20,0" VerticalOptions="CenterAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding Text, Source={x:Reference this}}" TextColor="{DynamicResource LabelColor}" Style="{StaticResource LabelText}" VerticalTextAlignment="Center" WidthRequest="30" />
<t:Button Grid.Column="1" Meta="GsT" RowId="{Binding RowId, Source={x:Reference this}}" State="{Binding State, Source={x:Reference this}}" TapCommand="{Binding TapCommand, Source={x:Reference this}}" Text="{Binding Message, Source={x:Reference this}}" Theme="{Binding Theme}" WidthRequest="30" />
</Grid>
</t:BaseGridTemplate>
从一些来源获取数据列表,将它们放入列表中
然后立即获取所有数据构建(所有100个AddSwitchRows)UI。 必须在屏幕上一次渲染数百个UI。 (即使用户不打算全部查看)
我强烈建议使用Listview。 或者用于网格的FlowListview https://github.com/daniel-luberda/DLToolkit.Forms.Controls
Listview只会尝试为用户正在查看的屏幕绘制UI。
如果还有一千件物品需要。 仅当用户向下滚动到该部分时才会构建它。
如果你想根据你收到的数据制作多种单元格,我们应该使用DataTemplate和ListView
示例在单击标题中的按钮时,我在listView的ItemSource中添加了1000个项目。 您可以在Listview.datatemplate标记中添加模板,并将ViewModel绑定到此视图View如果要根据属性值更改项目视图。 使用ListView的DataTemplate选择器属性
<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:stackAnswerApp"
x:Class="stackAnswerApp.MainPage"
x:Name="Root">
<ContentPage.BindingContext>
<local:MainPageViewModel />
</ContentPage.BindingContext>
<ListView ItemsSource="{Binding ListItems}" RowHeight="100">
<ListView.Header>
<Button Text="Start Adding" Command="{Binding StartAddingItems}" />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- whatever is your template -->
<StackLayout BackgroundColor="Aqua">
<Label Text="{Binding Text1}" />
<Button BackgroundColor="Blue"
Text="Go" BindingContext="{Binding Source={x:Reference Root},Path=BindingContext}"
Command="{Binding ButtonTapped}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
视图模型
class AModel
{
public string Text1 { get; set; }
public string Text2 { get; set; }
}
class MainPageViewModel
{
public ObservableCollection<AModel> ListItems { get; set; }
private const int TotalRows = 1000;
public ICommand StartAddingItems
{
get
{
return new Command(async () =>
{
//add too many items in the list
await Task.Run(async () => { await AddItemsToList(); });
});
}
}
private async Task AddItemsToList()
{
for (var i = 0; i < TotalRows; i++)
{
ListItems.Add(new AModel() {Text1 = $"index {i}", Text2 = $"tap {i}"});
}
}
public ICommand ButtonTapped
{
get
{
return new Command((() =>
{
//button in the list was tapped
}));
}
}
public MainPageViewModel()
{
ListItems = new ObservableCollection<AModel>();
}
}
如果订单很重要,我还没有看到另一种方法。 如果顺序无关紧要,您可以将StackLayout拆分为多个StackLayouts,并使用Task.WhenAll将各个元素添加到异步线程中。
Task.WhenAll就好像有多个人同时为你工作,而不只是一个人。
您可以尝试在stacks变量上使用BatchBegin(),然后在循环之后在您的函数AddSwitchRows和BatchCommit()中添加子循环。 如果可行,请在CreateSwitchSection中对父堆栈变量st执行相同操作。
IE浏览器。 stacks.BatchBegin(); foreach var x in data {...} stacks.BatchCommit();
这可以解决它,因为许多语言显示形式,例如每次(昂贵)添加/删除/更新集合/列表/子项时重新计算布局。 批处理允许布局重新计算一次,而不是每次列表更改。
我认为问题在App.cardSetWithWordCount中它可能是一个linq查询我认为每次都会转到db。只运行一次并保存在变量或属性上
var globalApp_cardSetWithWordCount = App.cardSetWithWordCount.ToList()
Linq在列表或toarray被调用时被执行。
List<int> ints = new List<int>();
foreach(var y in query)
ints.Add(y.Count());
return ints.ToArray();
然后使用相同的take和skip格式
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.