I broke down bigger "Razor page" views into to "Partial" views.
From the main views I pass e.g. an image list to the partial view:
<partial name="/Partial/_ImageList.cshtml" model="ImageList" />
These partial views now starts to grow, and gets less simple/clean/readable.
So to solve that, I looked into doing something like this, in either the main or partial view:
foreach (var item in Model.ImageList)
{
<partial name="/Partial/#item.some_property_view" model="item" />
}
With this I can have several smaller partial views, some also reusable cross different types of lists, instead of many if-then-else statement in a bigger view one.
To keep things simple/clean/readable, it appears (to me) this is the way to do it.
Given I have no long term experience with these things, and based on my own knowledge, where one learn about do's/dont's not found in any documentation;
Is there is anything else to consider, pros/cons when breaking down a bigger view to many smaller, that any of you ran into overtime?
My main concern is of course performance, though for a small number of items, 10-20, it likely wont matter, but will it if there are +200 items?...or at +1000?
I am aware of View Components, though I assume compiling many smaller of those, compared to Partial views, would have similar benefits/issues, but if not, please let me know.
Update
An ImageList item has about 5-8 properties, 1-2 is a header (50-100 characters each), 1-2 is a text (250-500 characters each), 1-2 is an image link and 1-2 is a hyperlink/anchor link.
As you noted - rendering a large amount of items is not recommended on both client and server side.
Why?
Server Side - require high computing + networking resources for a single connection and may overload the entire solution
Client side - overload the DOM with too much of HTML elements - most of them are not even viewable by the user in a given moment
Because this is a known issue, there is a solution to solve it - virtual scroll (aka infinite scroll) - which is the "modern" way to do pagination. In this excellent article there is a comparison between "classic" pagination and "modern" virtual scroll (at least in terms of user experience)
To the point: Microsoft provides a built-in virtualization mechanism to assist you solve this problem with ease (no need to implement your own pagination mechanism). The docs also provide a simple example to assist you keep going (before and after virtualization)
Based on the code you share I assume that you will change your loop from this
foreach (var item in Model.ImageList)
{
<partial name="/Partial/#item.some_property_view" model="item" />
}
to this
<Virtualize Items="Model.ImageList" Context="item">
<partial name="/Partial/#item.some_property_view" model="item" />
</Virtualize>
Because I really don't know how much data you load into you ImageList and if you need to reduce the number of items there - please refer to this part of the documentation in order to have a better control over your pagination mechanism (by loading current "page" of items instead of virtualizing the entire data set)
Good luck! 😊
Related
I am creating an MVC 4 application in ASP.NET 4.0. In my View I am displaying the Properties of a Model; one Property in particular may need to be hyperlink with a tooltip depending on another Property in the Model.
It's easier to explain by showing the code in the View:
#if (Model.HasMultipleErrorReasons)
{
<td data-toggle="tooltip" title="#Model.AllErrors">Multiple</td>
}
else
{
<td>#Model.Error</td>
}
I know there is nothing wrong with this and that it is functional, but I would prefer to not have to write out the <td></td> twice; the example above is very stripped down and in practice it is much messier.
Is there a way to avoid this or a better way to do it?
That's kind of the breaks of the game when working with templated rendering engines. You could abstract the code in some way so you don't have to see it, either using a partial view or a HtmlHelper extension. However, there's slight but not insignificant performance cost to using partial views, so if you end up with a ton of different partial views being rendered on the same page for multiple things like this, you'll feel it. This is also probably overkill for an extension. Although, if you can boil the code down enough that it would be applicable to a wide range of uses, it might warrant creating an extension method.
Overall, I would say just keep it as you have it.
I know this is a stupid question, I need to let you guys know that I am fully aware that it is useless in 99% of situations to make a listbox with this many elements in c#:
That being said I need this to be done...is there any way to populate a listbox with 40000 elements without it completely destroying performance/freezing up, thanks!
note: I have tried it, this is per the exact requirements of a professor...when adding 40000 elements through a DataSource and DataBind the application freezes up
You tell me.
for(i=0;i<40000;i++)
{
listBox1.Items.Add("click me");
}
Even if is possible (I never tried it), the usability for this form will be 0.
In that cases a more usable implementation is via lookup text-boxes and lists, where the user can enter a text to search record that matches this text and displays them in a any kind of list.
It is of course possible to do it, but not very practicable.
When using a desktop technology like WinForms or WPF, for a large number of items like this you are better off using something like an auto complete textbox, and have it set to filter/search after the user has typed two or three characters. In this case you can also use a control that offers scrolling virtualisation - this means that there is only a limited number of UI elements created in the scrolling portion of the dropdown, and those elements get reused when a scroll occurs. If you don't use virtualisation then a new element gets created for every list item that gets scrolled in to view. (Note that Silverlight controls have this functionality - just in case it's an option).
For ASP.NET though I would suggest that you do not want to do anything that would cause a large transfer of data (large items, or small items but lots of them) as it won't be performant. Instead you should look to do what Google does - retrieve search results in a paged fashion.
I'm new to Orchard CMS & MVC so please take this into account. Any help -the more the better- will be greatly received.
I want to add widgets to my blog summary page. What is the best way to achieve this? Ive tried creating a layer for the blog summary page defined by the rules for the layer, so as to be unique to this page. However, this only allows me to add widgets into the layer zones.
What i need/want to do is to effectively create a side bar with a tag cloud and a blogroll showing titles of other posts, and a couple of other bits of content. This would mean moving the blog summary content into another zone inorder that i can fit widgets down the side.
Is this the correct approach? If so how do i shift the summary stuff into another zone??
If this isnt the best approach, what is???
Is this where projections come in???
Thanks
from my understanding of your question, my answer goes like this.
If you are using the default ThemeMachine, the 'main content' i.e your Blog Summary Page, gets loaded into the Content Zone - which is in the middle container or zone of the ThemeMachine, and is flanked by two Aside Zones or commonly known as sidebars. To achieve what you are wanting I would place both the Tag Cloud widget and Blogroll widget into either the left Aside/Sidebar or right, depending on the look you are after.
And that's it!
Now this is dependent on the Theme you are using and that the Aside Zone(s) is actually available for use which is dictated by the Theme manifest, which is a Theme.txt file in the root of the Theme.
Now if you are wanting to set rules for when those widgets are shown, you can do this using Layers in the Widgets area in the Admin Dashboard. Details on that will require a second question ;-) as I've hopefully answered your first.
P.S. Projections can be used to substitute for both the Blog Summary Page and Blog widget. And can give finer control on what gets displayed.
I think I now understand what you're trying to accomplish and the solution requires you to modify your theme in one of two ways, whichever is most acceptable:
The first one is more preferable way but requires more work to be done. You should modify the Layout.cshtml template to split current Content zone in 2 - Content and Aside. This relies heavily on the current code of the template but it'll probably require changing from:
<section id="content-area">
#Zone(Model.Content)
</section>
to:
<section id="content-area">
#Zone(Model.Content)
</section>
#if(Model.Aside != null){
<aside id="aside-area">
#Zone(Model.Aside)
</aside>
}
Next, you'll need to change CSS so that your content-area is floating on the left, and the aside-area is floating to the right.
You'll also need to change Theme.txt file of your theme to add Aside in the list of zones.
You can now add widgets to the Aside zone. If those widgets should be shown only in specific circumstances, you'll have to make additional layer(s) that will be active for those circumstances when you want the widgets to be shown.
The second solution is for case you want those widgets to be shown only when the the blog is shown in summary mode. This solution is not a regular way of using Orchard, but rather a trick that Orchard allows but is not designed with this in mind. Nonetheless, I find it useful in certain cases, so here it goes.
Change Theme.txt to add Aside zone in the list of zones.
Create a new template in your theme and name it Content-Blog.cshtml. Edit it so that it has this content:
<section id="content-area">
#Display(Model.Content)
</section>
#if(Layout.Aside != null){
<aside id="aside-area">
#Display(Layout.Aside)
</aside>
}
You'll also have to make CSS changes to set your Aside zone to the right side of the content.
Now you can add your widgets to the Aside zone. Note that now you don't have to make new layers because the only time the Aside zone is shown is when the Content-Blog.cshtml is rendered and it's rendered only when showing Blog in summary mode.
In the end I was able to find the relevant view then switch the zones around so that the narrower zone appeared on the right. Then created a projection to return the blog post summary and placed this in the left hand larger zone.
Thanks to everyone that tried to help. I knew there had to be a simple answer, hence my initially simplified question. I didnt realise that would cause so much grief.
Details
VS-2008 Professional SP1
Version .net 3.5
Language:C#
I have a WPF Datagrid which loads from Linq-sql query Datacontext data item.The result set contains around 200k rows and its it very slow loading them,sorting,filtering etc.
What is the simple and easy way to improve the speed?
Couple of things I saw searching are
Scrollview,Data virtualization etc people also talk about Paging,Profiling etc
Loading data: 200k rows is a lot of data that no one (user) wants to see in one place. It will definitely reduce your UI user experience. So your best bet is to filter your data just to reduce the amount of it (for example do not show closed orders, just show the open ones). If you can't do so, you should use Virtualization. I didn't see any applications that use pagination in order to show data (Of course except in web). Most of the time it isn't such a good approach. But if you are talking about a type of data that is like search engines results you must use it. But keep in mind that most users won't exceed page 10 in search engines results.
Filtering: I would suggest doing it on your server side for such a huge amount of data (SQL Server here), or as I said first filter the whole 200k to reduce the amount on server side and then filter it (for user) in order to find something, on the client side. You might also find the following link helpful:
http://www.codeproject.com/KB/WPF/DataGridFilterLibrary.aspx
Sorting: Again I would suggest server-client solution but you might also find following links helpful:
http://blogs.msdn.com/b/jgoldb/archive/2008/08/26/improving-microsoft-datagrid-ctp-sorting-performance.aspx
http://blogs.msdn.com/b/jgoldb/archive/2008/08/28/improving-microsoft-datagrid-ctp-sorting-performance-part-2.aspx
http://blogs.msdn.com/b/jgoldb/archive/2008/10/30/improving-microsoft-datagrid-sorting-performance-part-3.aspx
Many people don't use default SortMemberPath of WPF datagrid just because it uses reflection on every single record and this will highly reduce the performance of the sorting process.
Hosein
Here is a very good sample of Data Virtualization (Not UI Virtualization):
http://www.codeproject.com/KB/WPF/WpfDataVirtualization.aspx
Althogh it doesn't support the LINQ IQueryable objects directly but you can use this sample as it is. Of course I'm now wokring to improve it to work with IQueryable objects directly. I think it's not so hard.
Wow, 200K rows is a lot of data. Paging sounds like a good idea. Try to decide how many rows per page you want, say 50. Upon showing the screen the first time, show only the first 50. Then give the user the option to move between pages.
Sorting might be trickier this way though.
Virtualization can be another option, sadly, I have yet to work with virtualization.
Sometimes you may have only ~30 visible rows to load and if those rows + whatever columns are expensive to load due to their number and complexity of the each cell (it's template, or how many wpf elements it has), none of the above comments really make a difference. Each row will take it's sweet time to load!
What helps is to stagger or lazily load each row on the UI, so that the user sees that the ui is doing something rather than just freezing for ~10+ seconds..
For simplicity, assuming that the datagrid ItemSource="{Binding Rows}", and Rows is IEnumerable, where Row is some class you created : add a property IsVisible to Row (don't forget to raise property changed, of course)
you could do something like this:
private void OnFirstTimeLoad()
{
Task.Factory.StartNew(() =>
{
foreach (var row in ViewModel.Rows)
{
/*this is all you really need,
note: since you're on the background thread, make sure IsVisible executes on the UI thread, my utils method does just that*/
myUtils.ExecuteOnUiThread(() => row.IsVisible = true);
/*optional tweak:
this just forces Ui to refresh so each row repaint staggers nicely*/
Application.Current.Dispatcher
.Invoke(DispatcherPriority.Background, (SendOrPostCallback) delegate { }, null);
}
});
}
oh, and don't forget to trigger in XAML:
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Visibility" Value="{Binding Path=IsVisible, Converter={StaticResource BoolToVisibility}}"/>
........
Is your datagrid inside a Scrollviewer? Because it does the entire datagrid (all the rows) to be rendered. I had a similar problem and removing the scrollviewer solved the problem with the slow loading.
Question that you should be asking is:
Are users groing to look through 200K rows of data?
How much data is too much for the users? May be alert the user that the query returned too many rows and you are listing the first 1000
Is it worth your time & money to program paging, Data Virtualization etc if users do not look beyond the first 1000 rows.
Ok, let me try to clearly explain what I'm attempting to accomplish here.
Basically, I have a site that is using a liberal dose of jquery to retrieve partialviews into a consolidated 'single view'. So far so good - it all works great and is very performant.
However, I would like to have the ability to 'flag' (using a button) any such set and as a consequence of flagging it, add it to a functional area that I have dubbed 'active-tasks'. What I'd like to do is to be able to then goto that 'active-tasks' panel and see a range of ui tabs that represented the consolidated views that I had added. Clicking on any tab would then re-invoke that consolodated view afresh with the parameters that had been used at the time of flagging it. This would therefore mean that I'd have to store the parameters (?) for creating that consolidated view, rather than the generated html (this part i can do at the moment).
So, any thoughts on how to elegantly store the code required to generate the consolidated view on clicking a tab button - no pressure :)
cheers - jim
Actually, after a minimal amount of research, it looks like the newly updated .data() jquery method (with the ability to add an object to the payload) may work for the above.
http://api.jquery.com/data/
basically, this allows you to add hash type keyed data to an id element for use later, so in my scenario above i could simply attach the parameters required to invoke the action method that related to my consolidated view on the tab.
I'll let you know how i progress with this...
jim