UWP VisualTreeHelper.GetParent() returns null - c#

I have a ContentDialog which has a ListView. This ListView's DataTemplate Contains a Grid and this Grid has a Button. The code goes like this:
<ContentDialog x:Name="DownloadListDialog" x:FieldModifier="public" Grid.Column="1">
<ListView Name="AssetsListView" IsItemClickEnabled="False" Grid.Row="1" SelectionMode="Single" MaxHeight="500" ItemsSource="{x:Bind _viewModel.Assets, Mode=OneWay}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
...
...
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate x:DataType="viewModel:AssetViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<TextBlock Text="{x:Bind name}"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind lblFileSize}"/>
<TextBlock Text="{x:Bind contentSize, Mode=OneWay}"/>
<TextBlock Text="{x:Bind contentUrl}" Visibility="Collapsed"/>
</StackPanel>
</StackPanel>
<Button Content="Download" Click="Button_Click" HorizontalAlignment="Right" Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentDialog>
Here's my Button Click event handler:
private async void Button_Click(object sender, RoutedEventArgs e)
{
var grid = VisualTreeHelper.GetParent(sender as Button) as Grid;
...
...
}
The problem is that the variable VisualTreeHelper.GetParent(sender as Button) as Grid always returns null on my PC. But this same code when I deploy on my mobile works perfectly fine (i.e, variable grid gets assigned the correct value).
UPDATE:
Here's my Live Visual Tree and it confirms that the button has a parent grid.
App min version: build 14393
App target version: Build 15063
PC windows version: Build 17134 (version 1803)
Note: I've tried changing the App target version to 1803 but the problem remains.

As I understand from a different question there are several ways to get the parent of the VisualTreeHelper. Could it be that on your mobile or PC for that matter in the background different things are loaded so that the location of where you can find the grid object changes.
You could check this answer as a reference of what I stated above: FrameworkElement.Parent and VisualtreeHelper.GetParent behaves differently

Related

UWP - can't access values in ItemsPanel

I have the following XAML but I can't seem to access the contents of the ItemsWrapGrid in the corresponding .CS file - can anyone tell me what I should be doing (here's the code behind and xaml) :
private void wifiTapped(object sender, TappedRoutedEventArgs e)
{
Debug.WriteLine("in here " + e.GetType().ToString());
ItemsWrapGrid wg = (ItemsWrapGrid) sender;
Debug.WriteLine(e.OriginalSource.ToString());
foreach (Control c in wg.Children)
{
Debug.WriteLine("Control " + c.Name);
}
Debug.WriteLine("leaving ");
}
<GridView VerticalAlignment="Top" ItemsSource="{Binding nets}" x:Name="GDView" ItemClick="gdViewClick" >
<GridView.ItemTemplate>
<DataTemplate x:Name="configDataTemplate" x:DataType="data:wifiNets" >
<StackPanel Height="300" Width="350" Margin="10" Name="dtStackPanel" >
<Image Source="Assets\wifiIcon.png" Width="200" Height="201" />
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name" Margin="0,0,10,0"/>
<TextBlock Name="configSSID" Width="auto" Text="{x:Bind NetSSID}" FontSize="24" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Strength" Margin="0,0,10,0"/>
<!--<TextBlock Name="configStrength" Width="auto" Text="{x:Bind NetSSIDStrength}" FontSize="20" />-->
<ProgressBar Name="configProgBar" Maximum="5" Value="{x:Bind NetSSIDStrength}" Foreground="Green" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Connected" Margin="0,0,10,0"/>
<TextBlock Name="configConnectedTo" Text="{x:Bind NetSSIDConnected}" FontSize="20"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid MaximumRowsOrColumns="10" Orientation="Vertical" Tapped="wifiTapped" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Just to be clear, when I run this I have three items of data (so it's working) - but what I'd like to be able to do is click on any one of the three data items and be able to identify the individual controls and their values within the data panel.
Thanks in advance, this is driving me nuts.
Paul.
Set IsItemClickEnabled to true on your GridView, and hook into the ItemClick event on the GridView itself. From the event args, you can get the sender (most likely the GridViewItem UI element itself, of which your DataTemplate content is a child), and the ClickedItem, which is the bound datacontext of the datatemplate - in your case the instance of the data:wifiNets - which if your bindings work mean you won't actually have to look in the VisualTree at all.
If for some reason you want to recurse through the VisualChildren for the items of any ItemsControl, use the ContainerFromIndex or ContainerFromItem methods on the ItemsControl to get the ItemContainer hosting each instance of the datatemplate - although I wouldn't recommend doing this unless you really need too. Ideally you shouldn't often have a need for manually trawling the visual tree.

UWP C# ListView not scrollable

I have this ListView:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer VerticalScrollBarVisibility="Visible" VerticalScrollMode="Enabled">
<ListView x:Name="entryList" Width="360">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel BorderBrush="Gray">
<TextBlock Text="{Binding title}"></TextBlock>
<TextBlock Text="{Binding description}"></TextBlock>
<TextBlock Text="{Binding author}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Grid>
I get my data for ItemsSource calling a webservice in a seperate method (works all fine)
private async void Page_Loading(Windows.UI.Xaml.FrameworkElement sender, object args)
{
entryList.ItemsSource = await webserviceManager.getItems(param1, param2);
}
My ListView is filled with items as well, but I can't figure out why it isn't able to scroll vertically. Checking the ScrollableHeight I get allways 0 so I think the items are the problem, the control doesn't count them as logical items so far. If I give the ScrollViewer a concrete height all is fine - but thats no viable solution for I don't know on which device the app will run later. So I have no faintest idea what I could do else, maybe somebody can help me?
Edit: the DataSource got a
ObservableCollection<entryObject> objlist = new ObservableCollection<NewsObject>();
where entryObject is a simple data holding class with string properties .
I've solved the Problem - by changing all StackPanels to Grids with RowDefinitions.
<ListView x:Name="entryList" Width="360">
<ListView.ItemTemplate>
<DataTemplate>
<Grid BorderBrush="Gray">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding title}" Grid.Row="0"></TextBlock>
<TextBlock Text="{Binding description}" Grid.Row="1"></TextBlock>
<TextBlock Text="{Binding author}" Grid.Row="2"></TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Also I changed my MainPage with the basic SplitView, where the frame in the content panel called the page with the ListView. Here has one of the Grid.Rows a constant height now - and, seems a little bit weird, but all is working fine now.
<SplitView.Content>
<Grid x:Name="mainPagePanel">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition></RowDefinition>
<Button x:Name="HamburgerButton" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent" Click="HamburgerButton_Click" Grid.Row="0"/>
<Frame x:Name="viewFrame" Grid.Row="1"></Frame>
</Grid>
</SplitView.Content>
ListView already contains ScrollViewer in Style. So, just remove your inner ScrollViewer.
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView x:Name="entryList" Width="360">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel BorderBrush="Gray">
<TextBlock Text="{Binding title}"></TextBlock>
<TextBlock Text="{Binding description}"></TextBlock>
<TextBlock Text="{Binding author}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

ScrollView not working in Windows 10

I have a ViewModel with about 200 contacts and I am binding it to a ListView
<Grid>
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ListView x:Name="ContactListing" ItemsSource="{Binding ContactListing}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DisplayName}" />
<Image Source="{Binding Thumbnail,Converter={StaticResource ResourceKey=contactConv}}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Grid>
Would be great if someone could explain the details behind the ScrollViewers visibility
A ListView control already contains a ScrollViewer and implements scrolling based on the amount of items, there is no need to wrap this control in another ScrollViewer. You can double check this in the default ControlTemplate of ListView at line 6219 in the generic.xaml file containing all Windows 10 styles:
C:\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\10.0.10240.0\Generic\generic.xaml
So you simply have to remove the ScrollViewer from your XAML fragment.
<Grid>
<ListView x:Name="ContactListing" ItemsSource="{Binding ContactListing}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=DisplayName}" />
<Image Source="{Binding Thumbnail,Converter={StaticResource ResourceKey=contactConv}}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
Note: As you're using a ListView, I suppose you want all your items stacked above each other. If you want multiple columns to show your items, use a GridView instead.

How to copy a selected text block to another hub page in Windows phone app

I am using list view to display a list of items in a group. Here is how my list view looks like:
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemListView"
AutomationProperties.Name="Items In Group"
TabIndex="1"
Grid.Row="1"
ItemsSource="{Binding Items}"
IsItemClickEnabled="True"
ItemClick="ItemView_ItemClick"
SelectionMode="None"
IsSwipeEnabled="false"
Margin="19,0,0,0">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="{ThemeResource ListViewItemPlaceholderBackgroundThemeBrush}" Margin="0,-9.5,0,0" Width="79" Height="79">
<Image Source="{Binding ImagePath}" Stretch="UniformToFill" AutomationProperties.Name="{Binding Title}" VerticalAlignment="Top"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="14.5,0,0,0">
<TextBlock Text="{Binding Title}" Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock Text="{Binding Description}" Style="{ThemeResource ListViewItemContentTextBlockStyle}" Foreground="{ThemeResource PhoneMidBrush}" TextWrapping="WrapWholeWords"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I would like to add a logic that when a text block is selected, it should copy the entire text block to another hub page (favorite) and create a reference back to the source text block. Whenever the user clicks any text block, it should be copied to the existing list of favorite blocks on Favorite hub page. Also, the user should be able to select the block on the favorite and remove it from the favorite list.
Currently, my "ItemView_ItemClick event looks like below which get the Id of the selecte item in the list, but I don't know how to proceed to implement above logic.
private void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
var itemId = ((SampleDataItem)e.ClickedItem).UniqueId;
if (!Frame.Navigate(typeof(ItemPage), itemId))
{
var resourceLoader = ResourceLoader.GetForCurrentView("Resources");
throw new Exception(resourceLoader.GetString("NavigationFailedException`enter code here`Message"));
}
You can use IsolatedStorageSettings for local storage.

Problems with flyout over itemscontrol in Windows Phone 8.1

I've got the following piece of XAML code:
<Grid Grid.Row="1" x:Name="ContentRoot" Margin="19,9.5,19,0">
<ScrollViewer>
<ItemsControl ItemsSource="{Binding History}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Tapped="HistoryItemTapped">
<FlyoutBase.AttachedFlyout>
<Flyout>
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer>
<TextBlock Foreground="{ThemeResource PhoneMidBrush}" FontSize="{ThemeResource TextStyleExtraLargeFontSize}" HorizontalAlignment="Left" Text="{Binding Expression}" />
</ScrollViewer>
<ScrollViewer>
<TextBlock FontSize="{ThemeResource TextStyleExtraLargePlusFontSize}" HorizontalAlignment="Right" Text="{Binding Result}" />
</ScrollViewer>
</StackPanel>
</Flyout>
</FlyoutBase.AttachedFlyout>
<TextBlock Foreground="{ThemeResource PhoneMidBrush}" FontSize="{ThemeResource TextStyleExtraLargeFontSize}" HorizontalAlignment="Left" Text="{Binding Expression}"
TextTrimming="CharacterEllipsis"/>
<TextBlock FontSize="{ThemeResource TextStyleExtraLargePlusFontSize}" HorizontalAlignment="Right" Text="{Binding Result}"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
There are two problems I can't solve:
The flyout is shown upon tapping on one of items:
private void HistoryItemTapped(object sender, TappedRoutedEventArgs e)
{
FlyoutBase.GetAttachedFlyout((FrameworkElement)sender).ShowAt((FrameworkElement)sender);
}
However, no matter how I set up the flyout it always shows on the top of the screen, not over the tapped item. Why?
The flyout contains two TextBlocks on separate ScrollViewers. The text on one of them exceeds width of the flyout, bt the scrollviewer does not appear to be working (I cannot scroll horizontally the textblock). Why is that?
So let's knock these out real quick. Your #1 would be expected result, it's just going off the default FlyoutPlacementMode enumeration wherein generally your flyout is just meant to appear over the top in one of 5 spots, Top, Bottom, Left, Right, or Full(Center)
How to fix it, ditch the flyout control and just animate your own panel to do the same thing on a tap event or whatever, not hard at all.
Your #2, if I remember right the default on ScrollViewerfor something like the HorizontalScrollBarVisibility is False by default. So just add HorizontalScrollBarVisibility="Auto" to it.
Hope this helps, cheers

Categories