How to add Parameters in ControlTemplate xamarin forms - c#

I have a template for HeaderItem with the imageSource in it, so all tabs have the same image. How can I bring an additional parameter to use different images?
Template
<ControlTemplate x:Key="HeaderControlTemplate">
<Grid HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Source="{converters:ImageResource Media.logo-pp.png}" Grid.Row="0" WidthRequest="25" />
<Label Grid.Row="1" Text="{TemplateBinding Text}" HorizontalTextAlignment="Center" StyleClass="tabViewHeaderTextColor"/>
<BoxView Grid.Row="2" IsVisible="{TemplateBinding IsSelected}"
StyleClass="tabViewHeaderBgColor"
HorizontalOptions="Fill"
HeightRequest="2" />
</Grid>
</ControlTemplate>
Tabs
<telerikPrimitives:RadTabView>
<telerikPrimitives:RadTabView.Items>
<telerikPrimitives:TabViewItem>
<telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewHeaderItem Text="1" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
</telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewItem.Content>
//SomeContent
</telerikPrimitives:TabViewItem.Content>
</telerikPrimitives:TabViewItem>
<telerikPrimitives:TabViewItem>
<telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewHeaderItem Text="2" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
</telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewItem.Content>
//SomeContent
</telerikPrimitives:TabViewItem.Content>
</telerikPrimitives:TabViewItem>
<telerikPrimitives:TabViewItem>
<telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewHeaderItem Text="3" ControlTemplate="{StaticResource HeaderControlTemplate}"/>
</telerikPrimitives:TabViewItem.Header>
<telerikPrimitives:TabViewItem.Content>
//SomeContent
</telerikPrimitives:TabViewItem.Content>
</telerikPrimitives:TabViewItem>
<telerikPrimitives:RadTabView>
TabViewHeaderItem also doesn't include the Image Source. So I don't know how to solve this. Sure I can do 3 templates, but it's not what i want.

I assume that Media.logo-pp.png is one of the 3 images you want to show. You could use the following trick to avoid duplicating templates:
First of all create a converter that will convert the tab name into the target image.
public class TabToImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string imageName;
switch (value.ToString())
{
case "1":
imageName= "logo-pp.png"
break;
case "2":
imageName= "logo-pp2.png"
break;
case "3":
imageName= "logo-pp3.png"
break;
default:
imageName= "logo-pp.png"
break;
}
return ImageSource.FromResource($"Media.{imageName}", this.GetType().GetTypeInfo().Assembly);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then change your template definition as follow:
add a new namespace for your converter class:
xmlns:converters="clr-namespace:Metadia.Converters"
add a static resource and reference the above converter
<ResourceDictionary>
<converters:TabToImageConverter x:Key="TabToImage" />
add a name to the label so it can be referenced
add binding to image source using the label's Text property and the converter
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Source="{TemplateBinding Source={x:Reference tabTitle}, Path=Text, Converter={StaticResource {TabToImage}}" Grid.Row="0" WidthRequest="25" />
<Label x:Name="tabTitle" Grid.Row="1" Text="{TemplateBinding Text}" HorizontalTextAlignment="Center" StyleClass="tabViewHeaderTextColor"/>
<BoxView Grid.Row="2" IsVisible="{TemplateBinding IsSelected}"
StyleClass="tabViewHeaderBgColor"
HorizontalOptions="Fill"
HeightRequest="2" />
</Grid>
Et voilĂ !
Note that if you rename the images the same as the tabs text, the converter could simply return (if not null):
return ImageSource.FromResource($"Media.{value.ToString()}", this.GetType().GetTypeInfo().Assembly);
Hope this helps & happy coding!

Related

Binding TopItem from SwipeView Xamarin to Collectionview from Viewmodel to Visibility of View

so i dont understand how to bind properly the TargetNullValue from TopItem to the Visibility of my grid View.
"""
<StackLayout HorizontalOptions="Fill" BackgroundColor="Yellow">
<AbsoluteLayout>
<Button x:Name="exit_button" Image="exit.png" Clicked="Exit_button_Clicked"
AbsoluteLayout.LayoutBounds="1,0,50,50" AbsoluteLayout.LayoutFlags="PositionProportional" />
</AbsoluteLayout>
<swipeCardView:SwipeCardView
x:Name="SwipeCardView"
ItemsSource="{Binding Pictures}"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
BackgroundColor="Red"
Padding="10"
SwipedCommand="{Binding SwipedCommand}"
DraggingCommand="{Binding DraggingCommand}"
Threshold="{Binding Threshold}"
SupportedSwipeDirections="{Binding SupportedDraggingDirections}"
SupportedDraggingDirections="{Binding SupportedDraggingDirections}"
AnimationLength="{Binding AnimationLength}"
>
<swipeCardView:SwipeCardView.TopItem>
<Grid IsVisible="{Binding TopItem , Source={x:Reference SwipeCardView}, TargetNullValue={Binding TopItem}}">
<StackLayout>
<Label Text="Keine Bilder mehr vorhanden" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
FontSize="Large" FontAttributes="Bold" BackgroundColor="AliceBlue"/>
</StackLayout>
</Grid>
</swipeCardView:SwipeCardView.TopItem>
<swipeCardView:SwipeCardView.ItemTemplate>
<DataTemplate>
<Grid ColumnSpacing="0" RowSpacing="0" BackgroundColor="Wheat">
<Grid.Resources>
<valueconverter:ByteArrayToImageSourceConverter x:Key="SourceConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="500" />
</Grid.RowDefinitions>
<Image Source="{Binding Image, Converter={StaticResource SourceConverter}}" Aspect="AspectFit" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"/>
</Grid>
</DataTemplate>
</swipeCardView:SwipeCardView.ItemTemplate>
</swipeCardView:SwipeCardView>
</StackLayout>
</ContentPage>
"""
There is clearly a wrong Binding, as i get the Error:
'Xamarin.Forms.Grid' cannot be converted to type 'System.Boolean'
'App1.Models.Pictures' cannot be converted to type 'System.Boolean'
So as i understand from TopItem, it turn to be null, if the Collectionview or Itemsource is null that means no items are left to swipe.
I want to set the Binding to the Top item, so that if there is no item left, thant the View Should be visible
You can use a converter to converter the TopItem into a boolean value.Such as:
public class TopItemToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TopItem top= value as TopItem;
if(top == null)
return false;
else
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Data Binding Xamarin Forms

Im quite new to xaml and xamarin.forms and I'm having some trouble with Data Bindings. I know there is a lot of similar questions out there but nothing I've found seem to work. My actual goal is to change background color when I turn a switch on and off. But for now I just want to make the binding work so I'm using a string in the example. My Page.xaml.cs looks like this
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CounterMainPage : ContentPage
{
public CounterMainPage ()
{
InitializeComponent ();
BindingContext = new CounterMainPageViewModel();
}
My viewmodel looks like this:
class CounterMainPageViewModel
{
public Color BackGroundColor = Color.Red;
public string Testning = "Urgent";
}
My Converter class looks like this:
public class BoolToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var valueAsString = value.ToString();
switch (valueAsString)
{
case ("Urgent"):
{
return Color.FromHex("#EF3D60");
}
case ("Not urgent"):
{
return Color.FromHex("#231F20");
}
default:
{
return Color.FromHex("#231F20");
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And last but not least my page.xaml looks like this:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:c="clr-namespace:BlankClient"
xmlns:local="clr-namespace:BlankClient"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BlankClient.View.CounterMainPage">
<!--Style="{StaticResource PageStyle}">-->
<ContentPage.Resources>
<ResourceDictionary>
<c:BoolToColorConverter x:Key="colorConverter"></c:BoolToColorConverter>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label x:Name="ReceivedFromServer" Text="" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
<Button Text="A" StyleId="0" Clicked="Button_Clicked" Grid.Row="1" Grid.Column="0"/>
<Button Text="2" StyleId="1" Clicked="Button_Clicked" Grid.Row="1" Grid.Column="1" />
<Button Text="3" StyleId="2" Clicked="Button_Clicked" Grid.Row="1" Grid.Column="2"/>
<Button Text="4" StyleId="3" Clicked="Button_Clicked" Grid.Row="2" Grid.Column="0"/>
<Button Text="5" StyleId="4" Clicked="Button_Clicked" Grid.Row="2" Grid.Column="1"/>
<Button Text="6" StyleId="5" Clicked="Button_Clicked" Grid.Row="2" Grid.Column="2"/>
<Button Text="7" StyleId="6" Clicked="Button_Clicked" Grid.Row="3" Grid.Column="0"/>
<Button Text="8" StyleId="7" Clicked="Button_Clicked" Grid.Row="3" Grid.Column="1"/>
<Button Text="9" StyleId="8" Clicked="Button_Clicked" Grid.Row="3" Grid.Column="2"/>
<Button Text="10" StyleId="9" Clicked="Button_Clicked" Grid.Row="4" Grid.Column="0" BackgroundColor="{Binding Testning,Converter={StaticResource colorConverter}}"/>
<Button Text="Undo" StyleId="Undo" Clicked="Button_Clicked" Grid.Row="4" Grid.Column="1" IsEnabled="False" />
<Button Text="Redo" StyleId="Undo " Clicked="Button_Clicked" Grid.Row="4" Grid.Column="2" IsEnabled="False"/>
<Switch Grid.Row="5" Grid.Column="0" />
</Grid>
<!--<StackLayout>
<Label Text="Counter Main Page" />
<Button Text="5" StyleId="5" Clicked="Button_Clicked"/>
<Button Text="10" StyleId="10" />
<Label x:Name="ReceivedFromServer" Text="ewq"/>
</StackLayout>-->
</ContentPage.Content>
First of all "public string Testning = "Urgent";" should be property to bind it to view. Read output and you will see that there is exception that "Testning" property is not found.
Second: you need to implement INotifyPropertyChanged interface (or use framework like Prism) to be able to change property value and inform UI about that change

Grouping ListBox with Date

I have no idea how to achieve this, but I have a date and time column in a ListBox. The Date column should not display if the date was already in there. I know that in combination with ListCollectionView and Listview/DataGrids, it is propably possible. But can I achieve this with a ListBox and a List. Keep in mind I am using the MVVM principle. This is my listbox:
<ListBox Grid.Row="2" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Schedules}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Transparent">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding MyDateTime, StringFormat='d' }" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding MyDateTime, StringFormat='t'}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding SomeText}" TextTrimming="WordEllipsis" LineStackingStrategy="MaxHeight" MaxHeight="20" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I have made this in excel to give an example of what I am trying to achieve:
I want the affect where I have highlighted with yellow
Converters
// Order Schedules using System.Linq
public class ToOrderedListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
List<ScheduleItem> schedules = (List<ScheduleItem>)value;
var subset = from item in schedules
orderby item.MyDateTime.TimeOfDay
orderby item.MyDateTime.ToString("yyyy/MM/dd") descending
select item;
return subset.ToList();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
// Show only first occurrence of date
public class DateToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
DateTime currentItem = (DateTime)values[0];
List<ScheduleItem> schedules = (List<ScheduleItem>)values[1];
ScheduleItem firstOccurrence =
schedules.Find(item => item.MyDateTime.Year == currentItem.Year
&& item.MyDateTime.Month == currentItem.Month
&& item.MyDateTime.Day == currentItem.Day);
if (firstOccurrence.MyDateTime == currentItem)
return Visibility.Visible;
else return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML
<ListBox Grid.Row="2" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Schedules, Converter={StaticResource ToOrderedListConverter}}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="Transparent">
<Grid Background="Transparent">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding MyDateTime, StringFormat='dd/MM/yyyy'}" HorizontalAlignment="Left" VerticalAlignment="Center">
<TextBlock.Visibility>
<MultiBinding Converter="{StaticResource DateToVisibilityConverter}">
<Binding Path="MyDateTime"/>
<Binding RelativeSource="{RelativeSource AncestorType={x:Type ListBox}}"
Path="ItemsSource"/>
</MultiBinding>
</TextBlock.Visibility>
</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding MyDateTime, StringFormat='t'}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Grid.Column="2" Grid.Row="0" Text="{Binding SomeText}" TextTrimming="WordEllipsis" LineStackingStrategy="MaxHeight" MaxHeight="20" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can use this approach for your requirements.
https://code.msdn.microsoft.com/windowsdesktop/CollectionView-Tips-MVVM-d6ebb4a7#content

Concatenate binding text and static text in source image

Is it possible to concatenate binding text with a static text in source image
For example:
<Image Name="ImagePlace" Source="http://site.com/image/architecture.png" Grid.Column="0" />
<Image Name="ImagePlace" Source="{Binding Path=Ico}" Grid.Column="0" />
And i would like to concatenate the two sources.
I have a list of object named Category that contains a field Icon that contains for example "architecture.png". I bind it in a list.
The url of site doesn't change but the image changes always.
<ListBox x:Name="ListboxCategories">
<ListBox.ItemTemplate>
<DataTemplate>
<Button Name="category" Tag="{Binding Path=Id}" Tap="category_Tap_1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Name="ImagePlace" Source="http://www.test.com/assets/images/icons/tags/architecture.png" Grid.Column="0" />
<TextBlock Text="{Binding Path=Title}" Grid.Column="1" HorizontalAlignment="Center" />
<Image Name="chevron" Grid.Column="2" Source="/Assets/AppBar/White/appbar.chevron.right.png" HorizontalAlignment="Right" Width="50" Height="50" />
</Grid>
</Button>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The cleanest way (well, depending on your architecture) would be to add a property in your object to do the concatenation:
public string FullUri
{
get
{
return "http://site.com/image/" + this.Ico
}
}
Another way is to use a custom converter to do the concatenation.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
{
return null;
}
return "http://site.com/image/" + value.ToString();
}

The Resource 'ImageConverter' could not be resolved

I'm new on Windows phone and silverlight development. During my learning exercises i have encountered an error which is i mentioned on the title of this post.
My main goal is saving and retrieving the image file to the SQLCE database, and i have used this tutorial http://antonswanevelder.com/2011/10/28/writing-an-image-to-sql-ce-linq-to-sql/
However, i had a problem with this code snippet
<Image Source="{Binding ItemImage, Converter={StaticResource ImageConverter}}" Stretch="UniformToFill"/>
My idea is compiler cannot locate the resouce ImageConverter. I really need a help on this.
My code is:
MainPage.xaml
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="CallListListBoxItemTemplate">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding CallName}" Foreground="DarkCyan" FontSize="{StaticResource PhoneFontSizeLarge}"
VerticalAlignment="Top" Margin="12,12,0,0"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="PersonalInfoListBoxItemTemplate">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Image Source="{Binding PersonImage, Converter={StaticResource ImageConverters}}" Stretch="UniformToFill" Name="_personPhoto" />
MainPage.xaml.cs
public class ImageConverters : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is byte[])
{
MemoryStream ms = new MemoryStream(value as byte[]);
WriteableBitmap wb = PictureDecoder.DecodeJpeg(ms, 100, 100);
return wb;
}
else
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Let's consider your value converter locates in ProjectName.Converters namespace.
In xaml you need to add a namespace:
<phone.PhoneApplicatinPage
.. all your code here
xmlns:converters="clr-namespace;ProjectName.Converters"
>
and in Resources tag:
<phone:PhoneApplicationPage.Resources>
<converters:ImageConverters x:Key="ImageConverter"/>
<!- your DataTemplates here-->
And small tutorial to make you more familiar with IValueConverter here

Categories