How to get the index of an item in an itemscontrol - xaml

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.

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...

Nested GridView Visibility is not working properly

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.

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>

Binding events to buttons in an ItemsControl

I have a windows phone 7 app with some xaml that looks like:
<Grid x:Name="ContentGrid" Grid.Row="1">
<ItemsControl x:Name="MyView" ItemTemplate="{StaticResource MyInner}"/>
</Grid>
The item template here looks like:
<DataTemplate x:Key="MyInner">
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource MyInner_Item}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</DataTemplate>
And finally, the MyInner_Item template looks like:
<DataTemplate x:Key="MyInner_Item">
<Button x:Name="MyButton">
<Button.Template>
<ControlTemplate>
<Border HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="myborder">
<Image Source="{Binding Path=ImageUri}" Width="{Binding Path=Width}" Height="{Binding Path=Height}" Stretch="Fill" />
</Border>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
So, it's an ItemsControl, which contains an ItemsControl, which contains buttons. This essentially creates a 2D array of buttons.
What I want to do is add an event handler to the Click event of the buttons.
Here's the catch: the code that sits behind this is written in F#. I can't, to the best of my knowledge, specify my event handler in the XAML, as F# doesn't talk to WPF in any nice way. So I need to add my event handler(s) manually in code.
Is there an easy way of doing this?
Currently, I have some F# which looks like:
let myView : ItemsControl = this?MyView
do myView.ItemsSource <- viewModel.BoardData
Here, the BoardData is a list of lists.
I was wondering if it's possible to loop through the controls in the ItemsControl, to add my event handlers? I'm having a bit of trouble doing this though. For example, in the following:
let container = myView.ItemContainerGenerator.ContainerFromItem(myView.Items.[0])
...sets container to null. In fact, all the methods I've tried from myView.ItemContainerGenerator returns null.
So, how should I go about attaching my event handler, so that I can respond to the buttons being clicked?
I have not done any Windows 7 Phone development, but I have done plenty of XAML + Silverlight development with C# and now I'm getting into doing some F# development. The approach I would take is by not using event handler's at all. Since you are using a button, make a class that derives from ICommand and add that type as a public property on your ViewModel so you could bind it to the Command property of the button. The benefits of using the ICommand interface over event handlers is that you could also have a condition on when the button is enabled to do the action.
Also, take notice that when you are doing binding expressions within (i.e. ItemTemplate) items in an ItemsControl control, the scope of what properties you can bind to are reduced to the properties of the current item. So all of the properties of the ViewModel are out of scope, unless you specify it fully i.e. <Button Command={Binding Source=ViewModel, Path=Property1.Property2.etc} />. Let me know if this helped.