Get dynamic bind listbox item - c#

I have the following listbox in my windows phone 8.1 silverlight application
<ListBox x:Name="ScenarioControl" FontFamily="Segoe WP">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Border Name="myborder" Margin="0,0,0,0" BorderThickness="0,0,0,3" BorderBrush="Black">
<Grid HorizontalAlignment="Stretch" Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Tap="TextBlock_Tap" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=Title, Mode=OneTime}" FontFamily="Segoe WP Semibold" Grid.Column="0" FontSize="23"/>
<Image Tap="Image_Tap" Source="/Images/blogger_small.png" HorizontalAlignment="Right" VerticalAlignment="Center" Grid.Column="1" OpacityMask="Black"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
As you can see TextBlock bound dynamically. I need to change some properties for the last TextBlock element but I cannot find method to get exact element inside the code.
I did search and found that there are solutions with ItemContainerGenerator method but that does not work for me, the following line of code always returns null.
ListBoxItem item = this.ScenarioControl.ItemContainerGenerator.ContainerFromIndex(ScenarioControl.Items.Count - 1) as ListBoxItem;

The most common cause of this problem is that the item in question isn't visible when you make the call to ItemContainerGenerator. Most listboxes, etc. virtualize their contents, meaning that they don't generate UI for elements that would not be visible to the user, so when you go to get the container, you just get null.
This Question + Answer(s) sums this up, and offers a solution to the problem.

Using a converter can help. It's not all declarative, but was what I thought initially.
Change style of last item in ListBox

Related

WPF Listbox items with name on mouseover or active

I've tried several different solutions to this, but can't land on one that meets all of my needs.
We have an observable collection of objects that each have a status and a name. It's a sort of task-list of running items. To display this list in WPF, we have some code that represents each item as an ellipse with some colors and animations.
The problem is that we want to display the name of the item as a 'popup' both on mouseover, or when the task is in a given state.
Attempt #1
My first attempt implemented this as a Datatemplate (to be used as an ItemTemplate) with an actual WPF Popup. I implemented two datatriggers - one for mouseover and one for task state. I positioned the popup based on my ellipse and everything was great. However, moving the window or switching to a different window left the popup on top of everything.
Attempt #2
Instead of using the popup I used a textbox in a canvas. This works great until the Datatemplate is used in the Listbox. The item host (stackpanel) ends up clipping the string.
Here's example code:
<DataTemplate x:Key="EllipseTemplate">
<Grid Height="40" Width="40">
<Canvas Name="PopupCanvas" HorizontalAlignment="Center" Width="500">
<TextBlock Name="PopupName"
Width="{Binding ElementName=PopupCanvas, Path=ActualWidth}"
Text="{Binding}"
Background="Transparent"
FontSize="16" HorizontalAlignment="Center" TextAlignment="Center" FontWeight="Bold"
Canvas.Top="-25"
Visibility="Collapsed"
/>
</Canvas>
<Ellipse x:Name="Ellipse" Height="25" Width="25" Margin="0"
HorizontalAlignment="Center" VerticalAlignment="Center"
Fill="Green"
RenderTransformOrigin="0.5, 0.5" StrokeThickness="0.5" Stroke="Black">
</Ellipse>
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver, RelativeSource={RelativeSource TemplatedParent}}" Value="True">
<Setter TargetName="PopupName" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<Grid Name="Test" Background="LightGoldenrodYellow" ClipToBounds="False" Margin="50">
<ListBox Name="OverlayTest"
Background="CornflowerBlue"
BorderThickness="0"
VerticalAlignment="Center"
Margin="10"
ClipToBounds="False"
ItemTemplate="{StaticResource EllipseTemplate}">
<sys:String>Very long string that will get clipped</sys:String>
<sys:String>Two</sys:String>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True" Margin="10,50,10,50" ClipToBounds="False"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
Attempt #3
I moved my canvas/textbox outside of the datatemplate and create a grid to put it above the listbox of ellipses. This works from a layout perspective, but creates a big mess in terms of checking for mouseover and centering the textbox on the control that's active/hovered.
So that leaves me without an implementation that works the way I want. Anyone have any suggestions?
Ok here I have another idea. I had problem with the ListBox before. Try replacing the ListBox with an ItemsControl.
Attempt #2 sounds like is working fine. You should be able to solve the issue of the clipping using one of these solutions (or all of them):
Set the ClipToBounds property of the ListBox to false
Set the ClipToBounds property of the Stackpanel to false

Column in UWP DataTemplate not stretching

I'm writing a UWP app to track TV shows watched/purchased/streamed etc and
am going absolutely crazy trying to get grid columns inside a DataTempate to stretch their width as it seems there is a bug in XAML which ignores the * width definition. I need the first column in the ListView (the show Title) to take up the remaining space (hence the column definition = "*") and while it will do that in the HeaderTemplate it absolutely refuses to do it inside the DataTemplate so the whole grid just ends up being all wonky and out of alignment as the Title column only uses the space it needs on each line.
My XAML is below - in the ItemTemplate DataTemplate template I am binding to an instance of an object called TVShow which is in an observable collection in my main view model. (I have not included the ViewModel or TVShow class definition here as I know this is a purely XAML issue).
The only thing that worked so far is having an extra property in my TVShow class that stores the correct width of the column (by subtracting the widths of the other three columns from the grid size (fetched in the view code behind) but this causes the whole list to reformat itself after initally displaying which looks ugly, not to mention awful programming.
So I'm looking for ideas on how to solve this - I could move the property for the correct column width in the main viewmodel but then how do I bind to that in the template given I am binding to "TVShow"? Or do I have to take the content out of the DataTemplate and put in a UserControl? I have wasted so much time on something that is so ridiculously simple - this bug seems to have been around since WPF so why haven't MS ever fixed this - very frustrating.
<HubSection Name="hsShows" Width="{Binding HubSectionWidth}" MinWidth="430" MaxWidth="640"
VerticalAlignment="Top" HorizontalAlignment="Stretch" Background="{StaticResource Dark}" >
<HubSection.Header>
<TextBlock Text="Shows" TextLineBounds="TrimToBaseline" OpticalMarginAlignment="TrimSideBearings"
FontSize="24" Foreground="{StaticResource Light}"/>
</HubSection.Header>
<DataTemplate x:DataType="local:MainPage">
<ListView Name="lvwShows"
Width="{Binding HubSectionGridWidth}"
Grid.Row="0"
Foreground="{StaticResource Light}"
Background="{StaticResource Dark}"
Margin="-14,20,0,0"
Loaded="lvwShows_Loaded"
ItemsSource="{Binding AllShows}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
IsSwipeEnabled="True"
IsItemClickEnabled="True"
SelectedItem="{Binding SelectedTVShow, Mode=TwoWay}"
SelectionMode="Single"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.VerticalScrollBarVisibility="Auto">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
<ListView.HeaderTemplate>
<DataTemplate>
<Grid Width="{Binding HubSectionGridWidth}" Height="Auto" Background="DarkGreen" Margin="15,5,5,5" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Title" FontSize="16" FontWeight="Bold" Foreground="{StaticResource Bright}"
VerticalAlignment="Bottom" HorizontalAlignment="Left"
Tag="TITLE,ASC" Tapped="ShowsGridHeading_Tapped"/>
<TextBlock Grid.Column="1" Text="Seasons" FontSize="16" FontWeight="Bold" Foreground="{StaticResource Bright}"
VerticalAlignment="Bottom" HorizontalAlignment="Center"
Tag="SEASONS,ASC" Tapped="ShowsGridHeading_Tapped"/>
<TextBlock Grid.Column="2" Text="Last Watched" FontSize="16" FontWeight="Bold" Foreground="{StaticResource Bright}"
VerticalAlignment="Bottom" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"
Tag="WATCHED,ASC" Tapped="ShowsGridHeading_Tapped"/>
<TextBlock Grid.Column="3" Text="Last Episode" FontSize="16" FontWeight="Bold" Foreground="{StaticResource Bright}"
VerticalAlignment="Bottom" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"
Tag="EPISODE,ASC" Tapped="ShowsGridHeading_Tapped"/>
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:TVShow">
<Grid Height="Auto" MinWidth="410" MaxWidth="640" Background="Blue" HorizontalAlignment="Stretch" RightTapped="ShowsList_RightTapped">
<FlyoutBase.AttachedFlyout>
<MenuFlyout Placement="Bottom">
<MenuFlyoutItem x:Name="UpdateButton" Text="Update from TVMaze" Click="FlyoutUpdateButton_Click"/>
<MenuFlyoutItem x:Name="RefreshButton" Text="Refresh" Click="FlyoutRefreshButton_Click"/>
<MenuFlyoutItem x:Name="DeleteButton" Text="Delete Show" Click="FlyoutDeleteButton_Click"/>
</MenuFlyout>
</FlyoutBase.AttachedFlyout>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="80"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{x:Bind Title}" Foreground="{StaticResource Light}"
VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Bind Seasons}" Foreground="{StaticResource Light}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="0" Grid.Column="2" Foreground="{StaticResource Light}"
Text="{x:Bind LastWatchedDate, Mode=OneWay, Converter={StaticResource DateTimeFormatConverter}, ConverterParameter='{}{0:dd/MM/yyy HH\\\\:mm}'}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<TextBlock Grid.Row="0" Grid.Column="3" Text="{Binding LastWatchedEpisodeRef}" Foreground="{StaticResource Light}"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</HubSection>
Ok, so I ended up adding this XAML into my ListViews (though I know I could have done what Grace suggested but I just find Blend horrific to use) - it was the HorizontalContentAlignment that actually did the trick!
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
If you have Correct width in viewmodel you can Bind it like this
Width={Binding ElementName = ListViewname,Path=DataContext.width}
This problem is caused by the default template of the ListViewItem, to make the Grid stretch inside of the items, you can open the Document Outline label => find your ListView control and right click on it, then choose Edit Additional Templates => select Edit Generated Item Container (ItemContainerStyle), and at last Edit a Copy.
Then you will find this template in your Page resources, please change the code:
<Setter Property="HorizontalContentAlignment" Value="Left" />
To:
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
Then your problem can be solved.
I saw you've more then one ListView, if you want this style target all the ListView in this page, you can remove the x:Key attribute of this template and remove the ItemContainerStyle with the StaticResource which is generated by the action upper.
Don't be frustrating, I think you have developed WPF before, it's easy to learn UWP. Editing the template or the styles of the controls can solve many layout problem, here is some default templates and styles of different controls, you may take a look next time you have such problem.
If you have questions about how to develop an UWP app, you can refer to Develop UWP apps, and if you have some problems with the APIs, you may refer to Reference for Universal Windows apps.
If you need help or suggestion, you may ask question here, people here are glad to help.

Styling ListView hovered/selected state for Universal Windows Platform

I would like to change the default styling of ListView in a Universal Windows Platform app. The default ListView item has a light gray color for hover, light blue for clicked, darker blue for selected item.
I tried to search and I have tried almost every piece of code, but without success. This is my xaml for ListView:
<Page.Resources>
<DataTemplate x:Key="MasterListViewItemTemplate" x:DataType="model:Thread">
<Grid Margin="0,11,0,13">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="35"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Ellipse Grid.Column="0" Width="35" Height="35" VerticalAlignment="Top">
<Ellipse.Fill>
<ImageBrush ImageSource="{x:Bind Photo}"/>
</Ellipse.Fill>
</Ellipse>
<TextBlock Grid.Column="1" Text="{x:Bind Name}"/>
</Grid>
</DataTemplate>
</Page.Resources>
<ListView
x:Name="MasterListView"
ItemContainerTransitions="{x:Null}"
ItemTemplate="{StaticResource MasterListViewItemTemplate}"
IsItemClickEnabled="True"
ItemClick="MasterListView_ItemClick">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
All this is defined in the ListViewItem style. You can override it and change the values you need easily. I will not copy-paste the complete style because it's huge and you can find it here.
You can also override just a few colors that bother you. At the same link you'll find that the ListViewItemPresenter has the properties such as SelectedPressedBackground set to ThemeResources.
SelectedPressedBackground="{ThemeResource SystemControlHighlightListAccentHighBrush}"
This means that overriding those can be the minimum you need to accomplish what you want (overried SystemControlHighlightListAccentHighBrush and so on), but have in mind that doing that will override those resources for the complete app, which may not be what you expect.

How to navigate to specifically position on ListBox Windows Phone 8.1

i have a listbox with a lot of items, and each items when clicked go to a new page, what i want is when i return from the second page, stay at the same position of the item is clicked!
Thats my list!
<ListBox x:Name="list" Loaded="ListView_Loaded" SelectedItem="true" SelectionChanged="searchResultsList_SelectionChanged" ItemsSource="{Binding}" Background="{x:Null}">
<!--<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Margin" Value="0,0,0,15" />
</Style>
</ListView.ItemContainerStyle>-->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Width="80" Height="80">
<Image Source="{Binding Caminho}" />
</Border>
<StackPanel Margin="0,16,0,0" Grid.Column="2">
<TextBlock Foreground="White" Text="{Binding NomeCurso}" TextWrapping="Wrap" FontSize="{StaticResource TextStyleExtraLargeFontSize}" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
thanks!
If you are using WinRT you can write the following code in your page constructor to cache it, this way the positions will be intact after you go back to this page:
this.NavigationCacheMode = NavigationCacheMode.Required;
And from your sample I cant really see if you are using ListBox or ListView, I will presume ListView which is better as the ListBox is somewhat not needed anymore.
One thing I also noticed is that you use a simple {Binding} for your ItemsSource so maybe it is reset every time you go back because of this (if you are doing something that does this, as this is not visible from your sample code). I always have an additional property of type ObservableCollection and bind to it for example ItemsSource={Binding MyItems}. This way the list is reset only when I reset the property MyItems.

UserControl in DataTemplate does not bind correctly

I've been trying to create a custom menu. For this reason I wanted to use an ItemsControl in order to make it flexible. After hours of headache I figured out how to make it - kinda.
I have my custom ItemsControl "LiftMenu" (which is not yet much custom but standard) and an UserControl called "LiftItem". Last but not least I got the Model-class "LiftMenuItem".
By adding a new LiftMenuItem to the LiftMenu, it should display a new LiftItem-control as corresponding item. So far so good, I managed to get this working.
In that LiftItem-control I bind like I would in a normal DataTemplate: plain bindings with a path, nothing more. Normally this would work just fine because the DataTemplate already has it's context set to the model-type.
But now I just get an empty control that does nothing and shows nothing, because the bindings don't work.
I implemented it this way:
<menu:LiftMenu HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="200" Background="#80A8A8A8" Margin="5,0,0,0">
<menu:LiftMenu.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</menu:LiftMenu.ItemsPanel>
<menu:LiftMenu.ItemTemplate>
<DataTemplate DataType="{x:Type menu:LiftMenuItem}">
<menu:LiftItem />
</DataTemplate>
</menu:LiftMenu.ItemTemplate>
<menu:LiftMenuItem Header="Test1"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Border x:Name="border" BorderBrush="{Binding LabelColor}" BorderThickness="1" HorizontalAlignment="Left" Height="Auto" Margin="0"
VerticalAlignment="Stretch" Width="4" Background="{Binding BorderBrush, ElementName=border}"/>
<TextBlock Text="{Binding Header}" TextTrimming="CharacterEllipsis" Margin="5,0,5,0" HorizontalAlignment="Left" VerticalAlignment="Center"
Foreground="White" />
<controls:ProgressRing x:Name="ring" Grid.Column="2" HorizontalAlignment="Right" Stroke="#ffff8000" VerticalAlignment="Center"
Minimum="0" Maximum="100" Value="{Binding ProcessValue}" IsIndeterminate="{Binding ProcessIndeterminate}" Visibility="{Binding ProcessVisibility}"
Width="20" Height="20" Radius="10" Margin="2,0,2,0" />
</Grid>
In the end there is no text, no border. Just the ProgressRing is visible.
How can I fix this? This ListItem-control should become similiar to a button, thus I need to do some styling (animation, ...). I can't do this within a normal DataTemplate, but I don't want to miss the binding features of WPF on that. This would make it relatively unflexible.
What's the problem? I probably just miss some DataContext or so, but I don't know what it would be.

Categories