Nested GridView Visibility is not working properly - xaml

I have a nested gridview. There seems to be a problem with the Visibility. In the code below, OuterCollection and InnerCollection have HideInUI property which I inverse to determine the visibility (ex. if true, hide).
However, on the 2nd HideInUI, if the 1st item is hidden, it seems to hide everything else.
<GridView x:Name="GridView_Outer"
InnerCollectionsSource="{Binding Path=OuterCollection}">
<GridView.InnerCollectionTemplate>
<DataTemplate>
<StackPanel Visibility="{Binding Path=HideInUI, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
<Button Content="{Binding Path=Title}"
IsEnabled="False"
Style="{StaticResource CategoryButton}"/>
<GridView x:Name="GridView_Inner"
InnerCollectionsSource="{Binding Path=InnerCollection}">
<GridView.InnerCollectionTemplate>
<DataTemplate>
<Button Width="120"
Command="{Binding ElementName=GridView_Outer, Path=DataContext.SelectPaymentTypeCommand}"
CommandParameter="{Binding Path=PaymentAmountTypeID}"
Content="{Binding Path=ScreenTitle}"
Visibility="{Binding Path=HideInUI, Converter={StaticResource InverseBooleanToVisibilityConverter}}">
</Button>
</DataTemplate>
Edit
Sorry for the confusion. But what happens is.
Ex. Category 1 has Item 1, Item 2, Item 3. If HideInUI is true in Item1, Item2 and Item3 becomes hidden also. But if Item 2 or Item3 is HideInUI instead, it works properly. I can't seem to find out why.

The issue you have here is that you are setting the visibility of the StackPanel(in your outer gridview) that contains the rest of your solution. You have to look at it as boxes, everything within it is affected by its parents in some ways.
The tabulation is a great way to help you understand which block contains what, in your example, you can clearly see that your GridView contains one thing, which is a DataTemplate. This DataTemplate also contains one thing which is the StackPanel, and so on. In your case, your StackPanel contains everything else, so if you hide it, you hide everything in it also.
What I think you actually want, it is to hide the button in the "Outer GridView", in this case, you should set visibility of the "Title" button instead of setting the visibility of the whole StackPanel.
Cutting and pasting your code:
Visibility="{Binding Path=HideInUI, Converter={StaticResource InverseBooleanToVisibilityConverter}}"
from your StackPanel to your "Title" button should do the trick.

Related

How to change the tab index in avalonia ui

In Avalonia Ui,
I have multiple layouts in my ui and I want a very specific tab order,
something like
<TextBox Tabindex="2">
<StackPanel>
<TextBox Tabindex="1">
</StackPanel>
<TextBox Tabindex="0">
that would result in using the tab-key cycling from bottom to top.
Is this possible? I found nothing.
I don't think so. KeyboardNavigation.TabIndex is not implmented yet: https://github.com/AvaloniaUI/Avalonia/issues/3025.
You have some limited Control using the functions provided in KeyboardNavigation and by using another control, for example a DockPanel or a Relative Panel.
Here is a very basic example for how you can use a DockPanel to do what you wish to:
<DockPanel LastChildFill="False"
VerticalAlignment="Top"
Name="TabOrderConatiner">
<TextBox Name="First" Tag="2" DockPanel.Dock="Top"></TextBox>
<TextBox Name="Third" Tag="0" DockPanel.Dock="Bottom"></TextBox>
<TextBox Name="Second" Tag="1" DockPanel.Dock="Top"></TextBox>
</DockPanel>
However it is like I said above limited compared to what TabIndex can provide.
Apart from that you should also be able to set the first TabItem when the container becomes active like that from your code-behind:
var tabOrderContainer = this.FindControl<DockPanel>("TabOrderConatiner");
var initialElement = this.FindControl<TextBox>("Third");
KeyboardNavigation.SetTabOnceActiveElement(tabOrderContainer, initialElement);
but I did not manage to get this to work...

Xamarin Forms - Multiple DataTemplate ListView

From my previous experience and some research on the web, I don't know if it's possible to have the following behavior:
<ContentPage.Content>
<AbsoluteLayout BackgroundColor="#2F767B">
<AbsoluteLayout x:Name="ScreenLayoutAdapter" BackgroundColor="#235A5E"
AbsoluteLayout.LayoutFlags="All">
<AbsoluteLayout.LayoutBounds>
<OnPlatform x:TypeArguments="Rectangle" Android="0, 0, 1, 1" iOS="1, 1, 1, 0.975" WinPhone="0, 1, 1, 1"/>
</AbsoluteLayout.LayoutBounds>
<ListView x:Name="ListViewCourses" BackgroundColor="Transparent" RowHeight="90"
AbsoluteLayout.LayoutBounds="0.5,1,0.9,0.9"
AbsoluteLayout.LayoutFlags="All">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<AbsoluteLayout Margin="2">
<!-- Your design for the cell template -->
</AbsoluteLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</AbsoluteLayout>
</AbsoluteLayout>
</ContentPage.Content>
In the c# side, I then have a ObservableCollection<Item> that I bind with the ListViewCourses.
But now my question is:
When I touch an item, how can I change of DataTemplate cell?
I mean, it's a list of items but when I touch one, I want that the cell grows up and displays more information, about the item selected.
If I have to bring more information to make you understand, tell me
Thank in advance ! :)
What you could do, instead of changing the DataTemplate of a single item, is have all of the controls containing the extra information that you want to show, be set to IsVisible = false and then when it is clicked, set IsVisible = true on all the controls and also call ListView.ForceLayout() to force the ViewCell to get redrawn.
Finally, make sure ListView.HasUnevenRows = true or else the ViewCell will not change size.
Alternatively, you may be able to add the controls containing extra information to the ViewCell when it is selected, it may or may not be slower/faster depending on the number of items in the ListView, the amount of extra controls you are adding, and whether you need to query the DB or a service for that extra information.
Let me know if you have any questions/issues.
Edit: Actually, you will want to call ViewCell.ForceUpdateSize(), info here, in order to change the size of the ViewCell once selected. You also may need to store that ViewCell instance in a class level variable so that you can shrink it back down when the user clicks a different ViewCell in the list.
Edit #2: One last thing I have run into, is that on iOS, if you have enabled ListViewCachingStrategy.RecycleElement on your ListView, you will most likely not see any change in the ViewCell after making controls visible and calling ForceUpdateSize(). This might have something to do with the last paragraph here, but I am not sure how to properly fix/get around it at this time.
Edit #3: For example you might do something like this:
<ViewCell>
<!-- Use ListView.ItemTapped instead of the TapGestureRecognizer below -->
<!-- <ViewCell.GestureRecognizers>
<TapGestureRecognizer Tapped="OnViewCellTapped"/>
</ViewCell.GestureRecognizers> -->
<StackLayout>
<!-- Main info displayed by default -->
<StackLayout StyleId="DefaultStackLayout">
<Label Text="{Binding ItemName}"/>
<Label Text="{Binding ItemDates}"/>
<Label Text="{Binding ItemCredits}"/>
</StackLayout>
<!-- Extra info displayed upon selection -->
<StackLayout StyleId="ExtraStackLayout"
IsVisible="False">
<Label Text="{Binding ItemBuilding}"/>
<Label Text="{Binding ItemTeacher}"/>
<Label Text="{Binding ItemHours}"/>
</StackLayout>
</StackLayout>
</ViewCell>
Then when the user selects the cell, you would need to do something like this:
using System.Linq;
...
private void OnViewCellTapped(object sender, EventArgs args) {}
tapCount++;
ViewCell viewCellSender = (ViewCell)sender;
StackLayout rootStack = (StackLayout)viewCellSender.View;
StackLayout extraInfoStack = rootStack.Children.Where(stack => stack.StyleId == "ExtraStackLayout");
extraInfoStack.IsVisible = true;
viewCellSender.ForceUpdateSize();
}
I have not tested any of this or even attempted it before, so if the above does not work, I am confident that inserting the extraInfoStack element content once the ViewCell is clicked, will work. But give the above a try first. Obviously you will need to change the layouts if you want to use AbsoluteLayout and you will also need to change the OnViewCellTapped() casting code.
Edit #4: I usually try to steer clear of constant numbers for height and width values if possible but sometimes it is unavoidable. So for this all to work you are going to have to set ListView.HasUnevenRows = true and that means you will need to get rid of your ListView.RowHeight value completely since the rows need to be allowed to have variable height.
If at all possible, I would try to not set a constants height value, but if you absolutely cannot live without setting the height to a constants value, then you can probably give your ViewCell's inner AbsoluteLayout a HeightRequest of 120, but then you would need to change that value when the item is selected, after making your extra controls visible and before calling ViewCell.ForceUpdateSize(). Setting IsVisible to false is supposed to make it so that the control does not take up any space, so those extra controls should not mess with the sizing while they are hidden but I have never tried it myself.
If you run into issues, please let me know.

Change ItemSize in ListPicker Windows Phone

I'm new to windows mobile apps.
I have a pivot page and inside that there is multiple pivot items.
Inside the pivot item there is list picker which values are hard coded.
If there is more items in list picker all items show in a new page by default.
My issue is since all the item font are too small when opening the screen.
How can I change the font size of list picker items when those are opening.
My code like this.
<toolkit:ListPicker Grid.Row="0" Grid.Column="2" FontSize="21" Header="" Margin="10,12,-157,12" Background="White" Foreground="Black" BorderThickness="1" >
<sys:String>Convenience Eateries (CE)</sys:String>
<sys:String>Grocery Store (GS)</sys:String>
<sys:String>Secondary Network-ASD</sys:String>
<sys:String>Secondary Network-PSD</sys:String>
<sys:String>Cash and Carry</sys:String>
<sys:String>Modern Trade-Convenience Organized</sys:String>
<sys:String>Modern Trade-Grocery independent(SMMT)</sys:String>
<sys:String>HoReCa-Leisure outlets</sys:String>
<sys:String>HoReCa-Sports Clubs</sys:String>
<sys:String>HoReCa-Night Clubs</sys:String>
<sys:String>HoReCa-Karaoke</sys:String>
<sys:String>HoReCa-Casino</sys:String>
<sys:String>HoReCa-Café and Restaurant/Pubs</sys:String>
<sys:String>HoReCa-Other</sys:String>
<sys:String>Military-Welfare Shop</sys:String>
<sys:String>Military-Canteen</sys:String>
<sys:String>Convenience Mobile Outlets</sys:String>
<sys:String>Unconventional Outlets-Wine Stores</sys:String>
<sys:String>Unconventional Outlets-Other</sys:String>
</toolkit:ListPicker>
Try using ListPickerItem children instead of strings. They should have a better default look than shown above:
<toolkit:ListPicker>
<toolkit:ListPickerItem>Bob</toolkit:ListPickerItem>
<toolkit:ListPickerItem>Betty</toolkit:ListPickerItem>
<toolkit:ListPickerItem>Frank</toolkit:ListPickerItem>
<toolkit:ListPickerItem>Frank</toolkit:ListPickerItem>
</toolkit:ListPicker>
To change how the items look in the full mode page, you need to change the ListPicker's FullModeItemTemplate property. Something like this:
<toolkit:ListPicker>
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="25" />
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
<sys:String>Convenience Eateries (CE)</sys:String>
<sys:String>Grocery Store (GS)</sys:String>
<!-- Hard coded values go here, just as in your code. -->
</toolkit:ListPicker>

Empty LongListSelector has infinite length

I have a LongListSelector which is inside a StackPanel. when this LLS is empty, it has infinite length and elements which are at the bottom of it can't be seen.
<StackPanel Orientation="Vertical">
<phone:LongListSelector>
</phone:LongListSelector>
</StackPanel>
but when I set it's ItemsSource, it gets fine. I tried assigning it's VerticalAlignment to top, but didn't solved the issue
How to make it's size not fill the form?
(I've edited this post to make it better)
First of all lets describe the problem you have, to do it we will use:
PROBLEM: infinite length of LongListSelector (LLS)- to be honest, it isn't a problem and it works like it should. Because LLS can have many many items and can be very long as its name says. The problem is that you use it in StackPanel without fixing its Height.
SOLUTIONS:
The first is very simple - just set the height of LLS. You will be sure that what should be below LLS, will be there. Like #Chris W mentioned - using LLS in StackPanel is not most forunate and can cause many problems - so avoid it.
<StackPanel Orientation="Vertical">
<phone:LongListSelector Height="300"/>
<TextBlock Text="Something/>
</StackPanel>
The most elegant and the best solution (also what #Chris W suggested) - to put your LLS into Grid. That way has many advantages and with Rowdefinitions your program will be independent of Phone resolution - all your controls will be there, were they should be.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<phone:LongListSelector Width="100" Grid.Row="0"/>
<TextBlock Text="Something" Grid.Row="1"/>
</Grid>
The third solution is not as good ad previous, but shows other way to manage your Controls. You can override the way LLS is measured. But with this method you have to watch out for example: it will work ok with the problem, unless you add so many items that your Controls will be pushed off the screen. Also you will have to watch out for this.Width, which has to be defined. So many additional conditions you have to check, of course you can add more modifications and it will work, but as I said it's not as good as previous solutions.
namespace Extensions
{
public class LongListSelectorEx : LongListSelector
{
protected override System.Windows.Size MeasureOverride(System.Windows.Size availableSize)
{
if (this.ItemsSource == null)
return new System.Windows.Size(this.Width, 0);
if (this.ItemsSource.Count <= 0)
return new System.Windows.Size(this.Width, 0);
return base.MeasureOverride(availableSize);
}
}
}
In your xaml you have to add:
<phone:PhoneApplicationPage
// something before
xmlns:common="clr-namespace:Extensions"
// other things
>
<StackPanel Orientation="Vertical">
<common:LongListSelectorEx Width="200"/>
<TextBlock Text="Something/>
</StackPanel>

How to get the index of an item in an itemscontrol

I want to show the current index of an item in an itemscontrol:
<TextBlock Foreground="#ffffffff" Margin="8,8,2,2" TextWrapping="Wrap" Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=Items.CurrentIndex}" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right"/>
This is my best guess. I've come across many possible solutions, but working with alternationcount (not supported in silverlight as it seems) or other didn't give me a result.
The itemscontrol looks like this:
<ItemsControl Grid.Column="0" Grid.ColumnSpan="3" HorizontalAlignment="Stretch" Grid.Row="6" ItemsSource="{Binding Alternatives, Mode=TwoWay}" ></ItemsControl>
The list bound to the itemscontrol is a simple object with some properties.
I really like to do this in XAML, as we reuse that object on alot of pages.
Any good suggestions would be great.
PS: I don't want the index after interaction from the user, it should be retrieved automatically.
if you want the index of an item in an itemscontrol - it just make sense for me if there is some sort of selection. but the itemsscontrol has no selector and so no selection and so no selectionchanged event. so if you want some selection take listbox
one more thing
<ItemsControl ItemsSource="{Binding Alternatives, Mode=TwoWay}" ></ItemsControl>
mode=twoway makes no sense, cause your itemsscontrol will never set the underlining source.
EDIT: i just assume what you want from your comment. you can use a ICollectionView to iterate through your items. but your Itemscontrol can not show this of course. but you can alter the item itself to show the iteration
ICollectionView view = CollectionViewsource.GetDefaultView(Alternatives);
view.CurrentChanged += (s,a) =>
{
var current = this.view.CurrentItem;
//to stuff with your current item here
};
elsewhere where you want to iterate
view.MoveCurrentToNext();
you should handle first and last item and that stuff too.