I'm new to Xamarin Forms, and am trying to create a page that has 4 sections of read-only data, one of which is a list of clickable items. In addition, the top section needs to be stationary (always on top).
My initial attempt was to use various StackLayouts, with a ScrollView to control this. There was much advice against putting a ListView in a ScrollView. After some struggles I got it to work, but then ran into an odd app crash on the ListView binding the second time a page is loaded (simple labels with the same binding are fine).
So my question is, should a ListView be used when many other elements are also on the page? If so, should the header and footer of the ListView contain the other controls, effectively making the ListView the root control? Is there an alternative suggestion to get a bound, clickable list on a page with other controls? Or maybe I'm running into difficulty simply due to the ListView needing to be in a ScrollView?
Related
I'm creating a Windows 10 Universal app, there are two panels in my main page.
In tablet/desktop mode, both are visible at the same time (just two simple Grids, one fills the left side and the other one fills the right side)
However, in phone mode, there's a pivot and user can swipe between panels.
(I could use SplitView and hamburger menus which work easily in both Tablet/Desktop and Phone modes, but a pivot makes more sense in my case)
So, What I currently did is, I have two instances of each panel. PhonePanel1 and PhonePanel2 are two grids inside two pages of my pivot control, and TabletPanel1 and TabletPanel2 are two grids which can be shown side by side. and I use AdaptiveTriggers to detect page width and switch between these two view methods.
However, having two instances of each panel is not a good approach, because those are showing basically the same content.
Is there any better approach to do this? Maybe changing Grid's parent when triggers are changing view mode? or something better?
The only way to change the parent that I can think of is to write some code behind that will render them in the new location. A suitable solution may be to defer the loading of the controls until they are needed.
x:DeferLoadStrategy=”Lazy“
If you add this property to your controls that are duplicated, they will only be loaded when required. So on a phone the PC/Tablet view should never be loaded, unless the user is running in Continuum on an external display.
On a PC you may still end up with both loaded (If the user resizes the window) - On a PC there are usually more resources so it's less of a problem there in most cases.
I looked into the code behind approach to move the controls to a different parent and I think honestly it's premature to do that when it might not even improve performance.
I have gone for the Defer Load Strategy property and found performance to be fine, and it requires very little code. My duplicate controls are sharing the same ViewModel so I pretty much just added the property to ensure resources are only used when essential.
There is nothing wrong in your approach. To reduce memory usage, when adaptive trigger happens for example on the phone, set TabletPanel1 and TabletPanel2 visibility to collapsed.
If all panels use the same datacontext then leave it as is, if not set datacontext for collapsed controls to null.
You could create each of your panels as user controls then you've only need to define the contents once but each control could be included in each of the layouts you want.
I have some trouble with ListView where the ItemsSource can be very important (over 5'000 items).
My application is that of a Chat Application consisting of two ListViews.
One on the left, the thread ListView showing a list of active thread
(conversation)
One on the right, the conversation ListView showing all messages exchanged.
I am using the DataTemplatepattern so that each item of my conversation ListView is customized as follow :
A chat Bubble using Coding4Fun package : http://www.geekchamp.com/articles/getting-started-with-the-coding4fun-toolkit-windows-phone-chatbubble-control
Each Chat Bubble has two TextBlock (one for the message content, the other for the timestamp).
Later, I intend to add pictures to this messages.
When user clicks on a conversation from the left-panel ListView, the main conversation ListView is loaded with the corresponding conversation (observable) collection.
If that collection is particularly big (in one case, I have more than 10'000 messages), the conversation ListView does show the content, but as soon as a switch to another thread and back to the previous, the content does not show anymore, although it's here, it's loaded. Starting to scroll, makes the ListView flickering and the content, therefore, is visible but severly flickering. If I stop scrolling, no content is showed, showing an empty list.
Further tests showed that this problem occurs only with large collection in concordance of usage of ScrollIntoView() method: indeed, I whish to show the bottom of my conversation ListView each time a user clicks on a thread so that he can read the last messages instead of the oldes, therefore saving him to have to scroll all the way to the bottom, each time.
I confirmed this issue by commenting out the line where I make the ListView to scroll to the bottom. The flickering problem is gone.
Finally, as I wrote my question, I found a stackoverflow question that seems to be my case: Windows Store universal app - ListView oddity
Unfortunately, the solution is not very clear. How can I solve my issue ? How should I use VirtualizingStackPanel/>inside a ListView that uses alread <ListView.ItemContainerStyle>, ListView.ItemTemplate>and <DataTemplate> ?
The solution to my flickering problem and how to implement UI Virtualization (normaly introduced in Windows 8.1) as described here https://www.microsoftpressstore.com/articles/article.aspx?p=2216995&seqNum=4 is as follow :
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
To be placed within a ListView scope !
Orientation must be defined ( Vertical | Horizontal ) otherwise a Critial Failure occurs !
UI Virtualization enhance large GridViews and ListViews so that huge amount data can be effeciently loaded without slowing down the UI nore blocking it for too long.
Honnestly the answer to your problem would be to redesign your application.
Never should there be so many items in a listview. You need to filter out some results
Example : Sort the question names /types/ etc and only show the corresponding (such as tags in Stack Overflow)
Only show the last lines of the conversation when you load it and allow the user to load more (like facebook's messenger)
Take a look at this C# listview maximum number of rows
As the answer says. The amount of items in your listview should be limited by common sense. 5k items in one listview is an incredibly high amount for a user to scroll through.
I am assuming your bubbles are in some kind of list or array. You can use Linq to get what you want. Take a look at this LINQ query to select top five
EDIT: I needed to skip control creation during post back -- see my answer below.
I'm working on a very basic front end to a simple tool and I wanted to present some data in a much more sorted and useful way, instead of making one huge wall of text. I found this tutorial on building a simple tabbed interface using MultiView, but have run into a bizarre problem. I can't use Ajax tabs because of legal hissy fits over 3rd party software.
My webpage is a basic ASP.NET page with a user control plopped in the middle of it. In this control's ascx file, I defined the Menu (empty) and the MultiView (also empty) so that I can dynamically populate the tabs with content driven from an external file.
When the default page's OnInitComplete function is called, I call through to the user control to load the data file, then build out the tabs and the view content based on the loaded data. I tried doing this from PageLoad, PreInit, and CreateChildControls, but I kept getting an errors saying that I was setting the the MultiView's active view index at an invalid time (and also that there were 0 views despite the fact I just added a bunch of them):
ActiveViewIndex is being set to '0'. It must be smaller than the
current number of View controls '0'. For dynamically added views, make
sure they are added before or in Page_PreInit event.
But OnInitComplete appears to work just fine, so I went with that.
I iterate over the loaded data (multiple lists of strings), and for each list, I add a MenuItem with the list's title to the Menu and a View to the MultiView. The View is populated with a table->row->cell as in the above tutorial. In the cell, I add the list title and a CheckBoxList data bound to the list of strings.
So far so good, but when I click on a tab (or one of the checkboxes, etc) and there is a postback or something like that (the screen flashes as the site redraws itself), there is now a duplicate set of MenuItems immediately after the original. Each time I click on a tab or checkbox, another set of menu items are added.
I clear the MenuItem's Items list prior to building the controls and I verify that the controls hierarchy is structurally as expected after the control construction. Yet when one of my callbacks is called, my MenuItem list magically has some items added to it. None of my other controls appear affected at all. As a hack, I can remove the duplicates manually in my menu's OnMenuItemClick event, but I'd have to do the same in any of the callbacks I receive. Obviously I'd rather prevent this from happening. This has me stumped and I haven't been able to find anything online about it. Why would one set of controls have some content duplicated, yet every other control maintain its state correctly? My code is really simple so there isn't a way to add additional menu items without also adding the views. Anyway, there are a correct number of items prior to clicking on the tab/checkbox, an additional set immediately following in the callback.
This is my first time using ASP.NET, so I'm learning as I go. :) Thanks!
My problem was that I was not testing for postback before creating the controls. The code below is working for me.
In my user control's code behind:
protected void OnInitComplete( EventArgs e )
{
if( !Page.IsPostBack )
{
CreateMyControls();
}
}
I have a grid view which has multiple items.
Each Item is a Webview. Now My issue is that I have a ComboBox above the GridView. When I select Combobox the drop down hides behind the GridView item (i.e Webview). Now I cannot use a WebViewBrush since I have multiple WebView items inside the grid view. Any suggestions?
XAML UI is always behind a WebView window - this is a typical airspace issue. You have to use WebViewBrush for any WebViews that might obscure your XAML controls. Some alternatives include modifying your UI layout - e.g. going to a separate page to display your selector control or moving ui elements about so they don't collide or implementing all of it in HTML.
In our project, SharpWired, we're trying to create a download component similar to the download windows in Firefox or Safari. That is, one single top down list of downloads which are custom controls containing progress bars, buttons and what not.
The requirements are that there should be one single list, with one element on each row. Each element must be a custom control. The whole list should be dynamically re-sizable, so that when you make it longer / shorter the list adds a scroll bar when needed and when you make it thinner / wider the custom controls should resize to the width of the list.
We've tried using a FlowLayoutPanel but haven't gotten resizing to work the way we want to. Preferably we should only have to set anchoring of the custom controls to Left & Right. We've also thought about using a TableLayoutPanel but found adding rows dynamically to be a too big overhead so far.
This must be quite a common use case, and it seems a bit weird to me that the FlowLayoutPanel has no intuitive way of doing this. Has anyone done something similar or have tips or tricks to get us under way?
Cheers!
/Adam
If you don't want to use databinding (via the DataRepeater control, as mentioned above), you could use a regular Panel control and set its AutoScroll property to true (to enable scrollbars).
Then, you could manually add your custom controls, and set the Dock property of each one to Top.
.NET 3.5 SP1 introduced a DataRepeater Windows Forms control which sounds like it'd do what you want. Bind it to the list of "downloads" (or whatever your list represents) and customize each item panel to include the controls you need.