UWP Semantic Zoom, ListView, VisualState - template10

<SemanticZoom x:Name="Zoom" >
<SemanticZoom.ZoomedInView>
<ListView Name="HotelInList"
IsItemClickEnabled="False"
Style="{StaticResource HotelListViewStyle}"
ItemContainerStyle="{StaticResource HotelListItemContainerStyle}"
ItemsSource="{Binding Source={StaticResource HotelViewSource}}"
ItemTemplate="{StaticResource HotelListItemTemplate}"
SelectedItem="{Binding Selected, Mode=TwoWay}" >
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="ItemClick">
<Core:GoToStateAction StateName="DetailVisualState" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
<ListView.GroupStyle>
The interactivity snippet above doesn't work. It will complain about how HotelInList doesn't contain a visual state named DetailVisualState, which is left out for brevity for now, but it is a visualstate above part of the rootlayout grid
Would nesting inside the SemanticZoom block the EventTriggerBehavior?

<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="ItemClick">
<Core:GoToStateAction StateName="DetailVisualState" TargetObject="{Binding ElementName=ThisPage}" />
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
Where ThisPage is the x:Name of the actual page, which forces the interaction to look down the resource tree and find from the the available resources the visualstate you requested.

Related

Correct AbsoluteLayout positioning/overlay

The main goal of the task to create AutoSuggest control.
In my case AutoSuggest control is custom control inherited from Grid
<Grid xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
xmlns:handlers ="clr-namespace:CrowdExchangeV2.Controls.Handlers"
WidthRequest="150">
<Grid.RowDefinitions>
<RowDefinition Height="35"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Frame Grid.Row="0"
...>
<handlers:BorderlessEntry Placeholder="{Binding Source={x:Reference this}, Path=Placeholder}"
WidthRequest="150"
.../>
</Frame>
<AbsoluteLayout
WidthRequest="150"
MaximumHeightRequest="100"
Grid.Row="1"
x:Name="resAl">
<ScrollView
MaximumHeightRequest="100"
MaximumWidthRequest="160"
x:Name="resSV">
<CollectionView x:Name="list">
<CollectionView.ItemTemplate>
<DataTemplate>
<HorizontalStackLayout VerticalOptions="Center"
HorizontalOptions="Start">
<Label Text="{Binding Key}" Padding="0,0,4,0"/>
<Label Text="{Binding Value}"/>
</HorizontalStackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
</AbsoluteLayout>
</Grid>
So, control looking for suggestions in Dictionary while user typing text in Entry. The thing is - when CollectionView updates suggestions it pushes all the other elements on ContentPage down... but suppose to overlay them. All right lets wrap Suggester in AbsoluteLayout on contentPage and setBounds to a desirable position. (PS: Suggester name is suggester 0_o)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
...
Title=" ">
<AbsoluteLayout x:Name="mainAbs">
<AbsoluteLayout Margin="0,0,0,0"
x:Name="suggestAl">
<suggester:Suggester Placeholder="USD"
SearchDictionary="{Binding SearchCurrency}"
MaximumHeightRequest="150"
MaximumWidthRequest="150"/>
</AbsoluteLayout>
<Grid Padding="10" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All">
<ScrollView>
<VerticalStackLayout>
...
<Frame HorizontalOptions="Fill">
<VerticalStackLayout>
...
<VerticalStackLayout HeightRequest="80"
x:Name="currVSL">
<Label Text="Currency out:"
VerticalOptions="Start"
HorizontalOptions="Start"
FontSize="Header"
x:Name="curLbl"/>
**SUggester should be here**
</VerticalStackLayout>
</VerticalStackLayout>
</Frame>
</VerticalStackLayout>
</ScrollView>
</Grid>
</AbsoluteLayout>
</ContentPage>
The first idea is - to grab x:Name="currVSL" bounds, adjust it for size of Label, and place x:Name="suggestAl" there, but i cant get absolute position of x:Name="currVSL" only relative and in absolute terms it's wrong
I don't want to hardcode position in static numbers, because the position highly depends on a particular device.
So the question is how to achieve a desirable result - Place x:Name="currVSL" under the x:Name="curLbl" label.
OR
Might be there is a more elegant solution to show suggestion results without pushing all the other elements down?(Read:overlay other elements on UI)
Image to visualise UI

TapGestureRecognition in Xamarin Forms Listview

I need to check if the empty part of a Xamarin Forms Listview is tapped. For example, there are 5 rows and the space below those filled rows is tapped a method should be called.
I tried adding Tapgesturerecognizer to the Listview and the page containing the listview but this didnt work.
Is there a way to check if someone tapped the empty space in the listview?
<ListView x:Name="ItemsListView"
ItemsSource="{Binding Items}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
RefreshCommand="{Binding LoadItemsCommand}"
IsPullToRefreshEnabled="true"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
CachingStrategy="RecycleElement"
ItemSelected="OnItemSelected">
<d:ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>First Item</x:String>
<x:String>Second Item</x:String>
<x:String>Third Item</x:String>
<x:String>Fourth Item</x:String>
<x:String>Fifth Item</x:String>
<x:String>Sixth Item</x:String>
</x:Array>
</d:ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="10">
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item descripton"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapGestureRecognizerTapped" NumberOfTapsRequired="1"></TapGestureRecognizer>
</ListView.GestureRecognizers>
</ListView>
Try to adding footer to the Listview
<ListView
x:Name="ItemsListView"
...>
<ListView.Footer>
<ContentView>
<ContentView.GestureRecognizers>
<TapGestureRecognizer />
<ContentView.GestureRecognizers>
</ContentView>
</ListView.Footer>
</ListView>
set footer view and place your TapGestureRecognizer
Checkout this https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/interactivity#selection-and-taps.
it discusses the selection activity in the ListView so u can execute some logic When an item is selected
Update:
Remove Code in the Screenshot then configure the ListView item selection as shown in the link.
then put the ListView (make sure that the list view fill only the space it needs) In a StackLayout and Configure the Tapped event of the stackLayout with the logic u need to execute on clicking the empty page.

Select ListView Element on button Click using MVVM

I have one list as RoomGroupList and another as RooList,One Room Group have multiple Roos in it, like
RoomGroup 1 => Room-1
Room-2
Room-3
I have bound RoomGroupList to ListView and RoomGroupControll is Generating From it as,
<ListView x:Name="lstRoomGroupList" SelectionMode="Single" ItemsSource="{Binding roomGroupList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding evokoRoomGroup,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<ListView.ItemTemplate>
<DataTemplate>
**<UserConrols:RoomGroupControl/>**
</DataTemplate>
</ListView.ItemTemplate
Now RoomGroupControl has one ListView to Listout No.ofRooms in it as,
<ListView x:Name="lstRoomList" Grid.Row="3" ItemsSource="{Binding GetroomList,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding DataContext.EvokoRoom,ElementName=tbDashBoard,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Stretch" VerticalAlignment="Top" Background="#F3F3F5"
BorderBrush="LightGray" BorderThickness="0"
Margin="0,0,0,0" Height="Auto" MaxHeight="200" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
**<UserConrols:RoomControl/>**
</DataTemplate>
</ListView.ItemTemplate>
what I want is,when I click on any button from ListElements at that time it's corresponding ListItem(row) should be selected so that I have added EventSetter using Resource on RoomGroupList as
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<EventSetter Event="PreviewGotKeyboardFocus" Handler="SelectCurrentItem"/>
</Style>
</ListView.Resources>
It's working properly for RoomGroupList I'm able to select Different Groups but Problem is I Can't select Rooms From RoomGroup which I have selected.
If anyone knows how to manage this, can also provide me Links and Suggestions,Thanks.

TreeView HierarchicalDataTemplate with Navigation Properties EntityFramework

I have three linked Entities (Categories->Types->Classes) with one to many relationship.
Is it possible to bind only Categories entity and represent the rest using Navigation properties andHierarchicalDataTemplate ?
I imagine something like this :
<TreeView ItemsSource="{Binding Categories}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Categories}" >
<TextBlock Foreground="Red" Text="{Binding Types}" />
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Classes}">
<TextBlock Text="{Binding TypeName}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding ClassName}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
I've done this recently, in a WPF project, I've updated the Types to match your names and Nav Properties.
You might want to consider changing Type/Class to something more specific since they're used as keywords in the c# language, but I think you get the idea
<!-- The Root Category Table -->
<HierarchicalDataTemplateDataType="{x:Type Entities1:Categories}" ItemsSource="{Binding Types}" >
<StackPanel Orientation="Horizontal">
<Image Name="img" Source="{Binding ., Converter={Converters:DataTypeImageConverter}}" />
<TextBlock Text="{Binding CategoryName}" FontWeight="Bold" />
</StackPanel>
</HierarchicalDataTemplate>
<!-- Your Type Table -->
<HierarchicalDataTemplate DataType="{x:Type Entities1:Type}" ItemsSource="{Binding Classes}" >
<StackPanel Orientation="Horizontal">
<Image Name="img" Source="{Binding ., Converter={Converters:DataTypeImageConverter}}" />
<TextBlock Text="{Binding TypeName}" />
</StackPanel>
</HierarchicalDataTemplate>
<!-- Your Class Table-->
<DataTemplate DataType="{x:Type Entities1:Class}">
<StackPanel Orientation="Horizontal">
<Image Name="img" Source="{Binding ., Converter={Converters:DataTypeImageConverter}}" />
<TextBlock Text="{Binding ClassName}" />
</StackPanel>
</DataTemplate>
What this will do is, it will match the datatype in the tree - If it matches Category, it will create the stackpanel, then start another branch, using the navigation collection Types.
For types, it will do the same basic thing - create the panel for that item, then another branch, for it's navigation collection Class.
If it's class, it will only create the panel, since it's a DataTemplate, not a HierarchicalDataTemplate

Own DataTemplateSelector MVVM

I'm using a MVVM-Pattern with a ModelView-First approach. This works fine, so far.
Now I have a UserControl (View) which should display various content depending on a Property located in my ViewModel.
First, I tried to solve the issue with DataTemplates and a DataTemplateSelector (See this tutorial) This was working very well. But I was not happy with the solution, because then I have a class (the overrided DataTemplateSelector) which is not connected to the ViewModel and can't be filled from the model.
So I tried to create a own TemplateSelector which uses a Property from the ViewModel. Unfortunately the DataTrigger is not triggering. The Binding from a CheckBox to the ViewModel is also working but not at the DataTrigger (even the designer can't find this path).
Ok, please have a look at the code:
<UserControl.Resources>
<!--Define Template which is displayed for Users-->
<DataTemplate x:Key="templateUser">
<Image
Name="logo"
Source="blanked out"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</DataTemplate>
<!--Define Template which is displayed for Administrators-->
<DataTemplate x:Key="templateAdmin">
<TextBlock Background="Yellow" Margin="3" Text="YEAH, I'm an Administrator" />
</DataTemplate>
<!--My own TemplateSelectpr-->
<DataTemplate x:Key="myTemplateSelector">
<ContentControl x:Name="DynamicContent" ContentTemplate="{StaticResource templateUser}"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsAdministrator}" Value="true">
<Setter TargetName="DynamicContent" Property="ContentTemplate" Value="{StaticResource templateAdmin}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentPresenter ContentTemplate="{StaticResource myTemplateSelector}"/>
</Grid>
Of course, I can seperate the Task in two further contentcontrols, but I don't want to maintain those if same content is intersecting.
So can someone suggest anything?
Best regards, and thanks in advance!
The simpler, the better: use a single template, which includes all the controls you need to show. Then switch their visibility using a binding to your property:
<UserControl.Resources>
<DataTemplate x:Key="myTemplate">
<Grid>
<Grid Visibility="{Binding IsAdministrator, Converter={StaticResource BooleanToVisibilityConverter}}">
<!-- Content for admin -->
</Grid>
<Grid Visibility="{Binding IsAdministrator, Converter={StaticResource NotBooleanToVisibilityConverter}}">
<!-- Content for user -->
</Grid>
</Grid>
</DataTemplate>
</UserControl.Resources>
<Grid>
<ContentPresenter ContentTemplate="{StaticResource myTemplate}"/>
</Grid>
Answer is to long for comment
Arnaud Weil brought me on the right way:
To access the Property 'IsAdministrator' in ViewModel from the Datatemplate, I gave the UserControl a Name e.g.:
<UserControl
x:Class="blanked out"
x:Name="this"
Used the code from Arnaud with some modifications, to inherit the Binding to the ViewModel from UserControl
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<helper:NotBooleanToVisibilityConverter x:Key="NotBooleanToVisibilityConverter"/>
<DataTemplate x:Key="myTemplate">
<Grid>
<Grid Visibility="{Binding DataContext.IsAdministrator, ElementName=this, Converter={StaticResource BooleanToVisibilityConverter}}">
<!-- Content for admin -->
<TextBlock Background="Yellow" Margin="3" Text="ICH BIN ADMNIN; JUCHUUU" />
</Grid>
<Grid Visibility="{Binding DataContext.IsAdministrator, ElementName=this, Converter={StaticResource NotBooleanToVisibilityConverter}}">
<!-- Content for user -->
<Image
Name="logo"
Source="/blanked out"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Grid>
</Grid>
</DataTemplate>
</UserControl.Resources>
And for the inverted BooleanToVisibilityConverter:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace blankedout.Helper
{
[ValueConversion(typeof(bool), typeof(Visibility))]
public class NotBooleanToVisibilityConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var boolValue = (bool)value;
return !boolValue ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Thanks once again to Arnaud Weil
Regards