How to write Iconverter for multiple converts - c#

Below is the code which im using to convert the values before binding to the listview. But here only the first 2 converts are working, the results for convert3 and convert4 are not getting displayed.please help me
<ContentPage.Resources>
<local:Class1 x:Key="_converter"/>
</ContentPage.Resources>
<ContentPage.Content>
<ListView x:Name="Models">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding from_time,Converter={StaticResource _converter}}"/>
<Label Text="{Binding to_time,Converter={StaticResource _converter}}"/>
<Label Text="{Binding from_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
<Label Text="{Binding to_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
public class Class1: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var str = (string)value; // value is the binding data
if (str== "00:00:00.0000000")
return "";
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Since it works on the first and second label , I think the issue is caused by the layout . In your case , the StackLayout will not aspect the size of its child elements in runtime .
You could use Grid .
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Label Grid.Row="0" HeightRequest="30" Text="{Binding from_time,Converter={StaticResource _converter}}"/>
<Label Grid.Row="1" HeightRequest="30" Text="{Binding to_time,Converter={StaticResource _converter}}"/>
<Label Grid.Row="2" HeightRequest="30" Text="{Binding from_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
<Label Grid.Row="3" HeightRequest="30" Text="{Binding to_time_tuesday,Converter={StaticResource _converter}}" TextColor="Brown"/>
</Grid>

Related

Change BackGroundColor to an element of the CollectionView

In a CollectionView I have items with a DateTime property, and at startup I select the item that matches today's date
public class DateColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (((DateTime)value).Date == DateTime.Today) return Color.Blue;
return Color.Gray;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
If I press on a different element, the element turns blue,
private void SelectedDate_Tapped(object sender, EventArgs e)
{
var model = (Grid)sender;
model.BackGroundColor=Color.Blue;
}
my CollectionView
<CollectionView
x:Name="ColCalendar"
RelativeLayout.YConstraint="{ConstraintExpression
Type=Constant,
Constant=68}"
RelativeLayout.WidthConstraint="{ConstraintExpression
Type=RelativeToParent,
Property=Width,
Factor=1}"
HeightRequest="45">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" ItemSpacing="7"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid BackgroundColor="{Binding Datet,Converter={StaticResource DateColor}}" RowSpacing="0.1" xct:TouchEffect.NativeAnimation="True" xct:TouchEffect.PressedBackgroundColor="LightGray" xct:TouchEffect.PressedOpacity="0.1">
<Grid.RowDefinitions>
<RowDefinition Height="9"/>
<RowDefinition Height="20"/>
<RowDefinition Height="8"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="43"/>
</Grid.ColumnDefinitions>
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="SelectedDate_Tapped"/>
</Grid.GestureRecognizers>
<Label Grid.Row="0" Text="{Binding Giorno}" FontSize="8" TextColor="White" HorizontalTextAlignment="Center"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
but I would like the one selected automatically to turn gray again.
How could I do?

Behaviors.Forms Command not Executing

I am attempting to upgrade an existing Xamarin project to the latest versions of various libraries. The Xamarin forms themselves live in a shared library. My page has a ListView on it & I am attempting to capture the event fired when an item is 'chosen'. However, the ICommand in my ViewModel is not executing.
NOTES:
I am using Xamarin.Forms 4.8...but had to downgrade Behaviors.Forms to 1.3 because the code is in a .NET Standard library.
If I upgrade to Behaviors.Forms 1.4 a design-time error occurs (see photo below)
SHARED LIBRARY INFORMATION:
.NET Standard 2.0
Acr.UserDialogs Version="7.1.0.454"
AzureMobileClient.Helpers Version="4.0.2.507-pre"
Behaviors.Forms Version="1.3.0"
Com.Airbnb.Xamarin.Forms.Lottie Version="3.1.3"
Prism.DryIoc.Forms Version="8.0.0.1850-pre"
Prism.Forms Version="8.0.0.1850-pre"
Refractored.MvvmHelpers Version="1.6.2"
Telerik.UI.for.Xamarin.Common Version="2020.2.624.1"
Telerik.UI.for.Xamarin.DataControls Version="2020.2.624.1"
Telerik.UI.for.Xamarin.DataGrid Version="2020.2.624.1"
Telerik.UI.for.Xamarin.Primitives Version="2020.2.624.1"
Telerik.UI.for.Xamarin.SkiaSharp Version="2020.2.624.1"
Xamarin.FFImageLoading.Forms Version="2.4.11.982"
Xamarin.FFImageLoading.Svg.Forms Version="2.4.11.982"
Xamarin.FFImageLoading.Transformations Version="2.4.11.982"
Xamarin.Forms Version="4.8.0.1364"
CONVERTER CLASS:
The original programmer returns 'ItemTapped' EventArgs...
public class SelectedItemEventArgsConverter : IValueConverter
{
#region <Methods>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var eventArgs = value as ItemTappedEventArgs;
return eventArgs != null ? eventArgs.Item : null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
VIEW MODEL:
The ListView binds-up & displays items (see photo's below)...
using CustomControls;
using Models;
using MvvmHelpers.Commands;
using Prism.Navigation;
using Prism.Services;
using System.Collections.Generic;
public class MainPageViewModel : ViewModelBase
{
#region Constructors
public MainPageViewModel(INavigationService navigationService, IPageDialogService pageDialogService, IDeviceService deviceService) : base(navigationService, pageDialogService, deviceService)
{
Initialize();
}
#endregion
#region <Properties>
public AccordionNode ShakeoutListItemsAccordion { get; private set; }
public Command<SimpleListItem> OnShakeoutListItemSelectedCommand { get; private set; }
public List<SimpleListItem> ShakeoutListItems { get; private set; } = new List<SimpleListItem>();
#endregion
#region <Events>
public async void OnShakeoutListItemSelected(SimpleListItem item)
{
if (item.Name == "Add Shakeout")
await NavigationService.NavigateAsync("ShakeoutDocumentGeneratorPage");
}
#endregion
private void Initialize()
{
// Commands
OnShakeoutListItemSelectedCommand = new Command<SimpleListItem>(OnShakeoutListItemSelected);
// Accordians
ShakeoutListItemsAccordion = new AccordionNode("OverwrittenInView", GlobalVariables.Accordion.Height, GlobalVariables.Accordion.HeaderBackgroundColor, GlobalVariables.Accordion.HeaderColorTextColor, GlobalVariables.Accordion.SeparatorColor);
// Data
ShakeoutListItems.Add(new SimpleListItem { Name = "Add Shakeout", Title = string.Empty, Type = string.Empty });
}
}
VIEW:
Because the converter-class 'ItemTapped' EventArgs, I am focusing-on that event...but I can chane this (if needed)
<?xml version="1.0" encoding="utf-8" ?>
<views:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:behaviors="clr-namespace:Behaviors;assembly=Behaviors"
xmlns:forms="clr-namespace:FFImageLoading.Svg.Forms;assembly=FFImageLoading.Svg.Forms"
xmlns:converters="clr-namespace:ETC.Operations.Pulse.Mobile.Converters;assembly=ETC.Operations.Pulse.Mobile"
xmlns:customControls="clr-namespace:ETC.Operations.Pulse.Mobile.CustomControls;assembly=ETC.Operations.Pulse.Mobile"
xmlns:helpers="clr-namespace:ETC.Operations.Pulse.Mobile.Helpers;assembly=ETC.Operations.Pulse.Mobile"
xmlns:views="clr-namespace:ETC.Operations.Pulse.Mobile.Views;assembly=ETC.Operations.Pulse.Mobile"
x:Class="ETC.Operations.Pulse.Mobile.MainPage">
<ContentPage.Resources>
<ResourceDictionary>
<converters:SelectedItemEventArgsConverter x:Key="EventToCommand"/>
<forms:SvgImageSourceConverter x:Key="SvgImageSourceConverter"></forms:SvgImageSourceConverter>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<ScrollView VerticalOptions="FillAndExpand" Padding="10">
<StackLayout Spacing="0" Padding="0">
<!-- SHAKEOUTS -->
<StackLayout Spacing="0" Padding="0" Style="{DynamicResource AccordionTitleStyle}">
<StackLayout Style="{DynamicResource AccordionHeaderStackLayoutStyle}">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ShakeoutListItemsAccordion.ExpandContractAccordion}"/>
</StackLayout.GestureRecognizers>
<Label Text="Shakeouts" Style="{DynamicResource AccordionHeaderTextStyle}" VerticalTextAlignment="Center"/>
<Label TextColor="{Binding ShakeoutListItemsAccordion.HeaderTextColor}" HorizontalOptions="EndAndExpand" Text="{Binding ShakeoutListItemsAccordion.IconText}" VerticalTextAlignment="Center"/>
</StackLayout>
<BoxView HeightRequest="1" Color="{Binding ShakeoutListItemsAccordion.LineColor}" HorizontalOptions="FillAndExpand"></BoxView>
</StackLayout>
<!-- SHAKEOUTS: Controls -->
<StackLayout BackgroundColor="{DynamicResource BackgroundColor}" HeightRequest="200" IsVisible="{Binding ShakeoutListItemsAccordion.IsExpanded}" Padding="0" Spacing="0">
<ListView
x:Name="lvShakeoutListItems"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
ItemsSource="{Binding ShakeoutListItems}"
RowHeight="40">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Style="{DynamicResource ListViewGridItemStyle}" RowSpacing="0" ColumnSpacing="0" Margin="13,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Name}" Style="{DynamicResource ListViewLabelCenterRowLeft}" TextColor="{StaticResource LabelValueTextColor}" Margin="0,10,0,0"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<behaviors:EventHandlerBehavior EventName="ItemTapped">
<behaviors:InvokeCommandAction Command="{Binding OnShakeoutListItemSelectedCommand}" Converter="{StaticResource EventToCommand}" />
</behaviors:EventHandlerBehavior>
</ListView.Behaviors>
</ListView>
</StackLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</views:BaseContentPage>
PHONE IMAGES:
As you can see...the ViewModel is binding to data.
NOTES:
Upgrading to Behaviors.Forms 1.4 generates a design-time error.
UPDATES:
Here are my updates on the suggestions being made by contributors...
The 'Tap gesture on main cell object' option does not fire an event (at all)
The 'selected Item' event raises...but does not call the "MainPageViewModel OnShakeoutListItemSelected" event
I am currently looking at "Corcav Behavior" in NuGet
Option 1 : Use tap gesture on main cell object
<ListView
x:Name="lvShakeoutListItems"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
ItemsSource="{Binding ShakeoutListItems}"
RowHeight="40">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Style="{DynamicResource ListViewGridItemStyle}" RowSpacing="0" ColumnSpacing="0" Margin="13,0,0,0">
**<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding OnShakeoutListItemSelectedCommand}" CommandParameter="{Binding .}"/>
</Grid.GestureRecognizers>**
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.8*" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding Name}" Style="{DynamicResource ListViewLabelCenterRowLeft}" TextColor="{StaticResource LabelValueTextColor}" Margin="0,10,0,0"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Option 2: Use selected Item on main cell object
<ListView
x:Name="lvShakeoutListItems"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
ItemsSource="{Binding ShakeoutListItems}"
SelectedItem="{Binding SelctedItem}"
RowHeight="40">
...
</>
Option 3 : Use corcav behavior nuget to get event to command behavior

How to change frame's background color in code behind?

I am creating an app for android, iOS and WP using xamarin. in one of my pages, i have a frame inside a datatemplateand i can't acess frame element in code behind, so i bind backgroundcolor of frame to a variable. And when user clicks on a button, the color should change but it does not.
XAML :
<CollectionView x:Name="collectionView">
<CollectionView.EmptyView>
<Label Text="Não foram encontrados contactos com email" x:Name="SemContactos" IsVisible="False" AbsoluteLayout.LayoutBounds="0.5,0.5,100,100" AbsoluteLayout.LayoutFlags="PositionProportional"/>
</CollectionView.EmptyView>
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate x:Name="template">
<Grid Padding="5" x:Name="grid">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70"/>
<ColumnDefinition Width="70"/>
</Grid.ColumnDefinitions>
<Frame BackgroundColor="{DynamicResource myResourceKey}"
OutlineColor="LightGray"
CornerRadius="3" Padding="0.5" Grid.RowSpan="3" Grid.ColumnSpan="5" x:Name="frameContacto">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="ContactoSelecionado" />
</Frame.GestureRecognizers>
<StackLayout Spacing="5">
<Image x:Name="imageX" Grid.RowSpan="2" Grid.ColumnSpan="2"
Source="{Binding Foto}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60"
HorizontalOptions="Center" />
<!--Source="{local:ImageResource KiaiDay.Images.user.png}"-->
<Label Grid.Row="2" Grid.ColumnSpan="2" Text="{Binding Nome}" FontAttributes="Bold" HorizontalOptions="Center" VerticalOptions="EndAndExpand" TextColor="Black"/>
<Label Grid.Row="3" Grid.ColumnSpan="2" Text="{Binding Email}" HorizontalOptions="Center" VerticalOptions="StartAndExpand"/>
</StackLayout>
</Frame>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<StackLayout AbsoluteLayout.LayoutBounds=".5,1,.5,.1" AbsoluteLayout.LayoutFlags="All" x:Name="butoes" IsVisible="False">
<StackLayout Orientation="Horizontal" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Button Text="Seleccionar todos" WidthRequest="170" TextColor="White" BackgroundColor="#1E90FF" FontAttributes="Bold" CornerRadius="2" HeightRequest="40" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Clicked="SeleccionarTodos" x:Name="selTodos"/>
<Button Text="Convidar" WidthRequest="170" TextColor="White" BackgroundColor="#1E90FF" FontAttributes="Bold" CornerRadius="2" HeightRequest="40" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</StackLayout>
And C#
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ConviteEmailPage: ContentPage {
Color corFrame = Color.White;
public ConviteEmailPage() {
this.Resources.Add("myResourceKey", corFrame);
InitializeComponent();
}
private void SeleccionarTodos(object sender, EventArgs e) {
if (selTodos.Text == "Desmarcar") selTodos.Text = "Seleccionar Todos";
else selTodos.Text = "Desmarcar";
corFrame = Color.LightGray;
}
From code , Frame's color is in CollectionView.ItemTemplate.If want to change color in Item, you should change model's data ,not directly change by binded Resource name or x:Name to do that.
In model add MyColor property to model Monkey:
private string mycolor = "Accent";
public string MyColor
{
get
{
return mycolor;
}
set
{
if (mycolor != value)
{
mycolor = value;
OnPropertyChanged("MyColor");
}
}
}
If want be changeg dynamiclly , also need INotifyPropertyChanged to model:
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Then bind MyColor in Xaml :
<ContentPage.Resources>
<ResourceDictionary>
<CollectionViewDemos:StringToColorConverter x:Key="StringToColorConverter"/>
</ResourceDictionary>
</ContentPage.Resources>
Frame BackgroundColor="{Binding MyColor, Converter={StaticResource StringToColorConverter}}"
It also need IValueConverter to convert color from string:
public class StringToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//throw new NotImplementedException();
string valueAsString = value.ToString();
switch (valueAsString)
{
case ("Red"):
{
return Color.Red;
}
case ("Accent"):
{
return Color.Accent;
}
default:
{
return Color.FromHex(value.ToString());
}
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Last , you can test when CollectionView SelectedItem
<CollectionView ItemsSource="{Binding Monkeys}"
SelectionMode="Single"
SelectedItem="{Binding SelectedMonkey, Mode=TwoWay}">
Adding selectedMonkey to MonkeyList model. When selected, changed color to red as follow:
Monkey selectedMonkey;
public Monkey SelectedMonkey
{
get
{
return selectedMonkey;
}
set
{
if (selectedMonkey != value)
{
selectedMonkey.MyTextColor = "Red"; //Here is changing the color
selectedMonkey = value;
}
}
}

XAML Binding issues in Xamarin.Forms

I have created a ViewCell that can be reused throughout my project:
<?xml version="1.0" encoding="UTF-8"?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:C="using:****.Converters"
x:Class="****.Views.Settings.SettingCell">
<Grid BackgroundColor="{StaticResource BlueGray}">
<Grid.Resources>
<C:DebugConverter x:Key="debugConverter"/>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{Binding ImageSource}"/>
<Label Grid.Column="1"
Text="{Binding Path=Title,
Converter={StaticResource debugConverter},
FallbackValue=Title}"
HorizontalOptions="Start"
VerticalOptions="Center"/>
</Grid>
</ViewCell>
Here is ViewModel:
public partial class SettingCell : ViewCell
{
public SettingModel Model
{
get
{
return model;
}
set
{
model = value;
BindingContext = value;
}
}
public SettingModel model;
public static readonly BindableProperty SettingTypeProperty = BindableProperty.Create(nameof(SettingType), typeof(Setting), typeof(SettingModel));
public Setting SettingType
{
get
{
return (Setting)GetValue(SettingTypeProperty);
}
set
{
SetValue(SettingTypeProperty, value);
}
}
public SettingCell()
{
InitializeComponent();
switch (SettingType)
{
case Setting.Name:
Model = new NameSettingModel();
break;
default:
throw new NotImplementedException("Unknown Setting Type");
}
}
}
The Model is a subtype of an abstract class that is selected through a class discriminator. The class is very simple at this point since I'm just getting it wired up, but here is the base class along with on sub-type:
public class NameSettingModel : SettingModel
{
public NameSettingModel()
{
Title = "Name";
IconSource = "";
}
public override void ClickCommand()
{
Debug.WriteLine("Setting Command Run");
}
}
public abstract class SettingModel : BindableBase
{
public string Title
{
get
{
return GetProperty<string>();
}
set
{
SetProperty(value);
}
}
public string IconSource
{
get
{
return GetProperty<string>();
}
set
{
SetProperty(value);
}
}
public abstract void ClickCommand();
}
BindableBase is just a base binding class that implements INotifyPropertyChanged and stores property values in a dictionary so I don't have to make a field for each property.
When I run the project; the fallback value shows up each time. The thing that strikes me as odd is that when I put a break in my debugConverter which is as follows:
public class DebugConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I see the value "Name" coming through the converter but the UI only ever shows the fallback value. Any ideas? Any reason that the binding would get the correct value but just not refresh to display it? I'm at a loss here. I'm happy to post any more code that could be helpful, just leave me a comment.
Thanks!
=========================== Edit =============================
The plot thickens. I now have a viewcell that is directly in my listview and the template I have inserted is just a Grid.
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:Images="clr-namespace:MyApp.Images;assembly=MyApp"
xmlns:Converters="clr-namespace:MyApp.Views.Converters"
x:Class="MyApp.Views.Templates.SettingTemplate"
BackgroundColor="White" VerticalOptions="Center">
<Grid.Resources>
<Converters:SettingToIconConverter x:Key="SettingToIconConverter"/>
<Converters:InverseBoolConverter x:Key="InverseBoolConverter"/>
</Grid.Resources>
<StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
<Images:VectorImage ResourceId="{Binding Converter={StaticResource SettingToIconConverter}}"
WidthRequest="30" HeightRequest="30" Margin="2" VerticalOptions="Center"/>
<Label Text="{Binding Name, FallbackValue=Name}" FontAttributes="Bold" FontSize="Medium" Margin="2"
VerticalOptions="Center"/>
<ContentPresenter Content="{Binding BonusContent}" VerticalOptions="Center" Margin="2"/>
</StackLayout>
<Frame BackgroundColor="{StaticResource Slate}" Opacity="0.25" IsVisible="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Converter={StaticResource InverseBoolConverter}, FallbackValue=false}"/>
Here's the containing listpage that has two templates in it:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
<RowDefinition Height="1"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Templates:PeripheralDetailsTemplate/>
<Frame BackgroundColor="{StaticResource Slate}" Grid.Row="1"/>
<Frame BackgroundColor="White" Grid.Row="2">
<ListView x:Name="lvPeripheralSettings" ItemsSource="{Binding Settings}"
SelectionMode="None" ItemTapped="Setting_Tapped" RowHeight="40"
ios:ListView.SeparatorStyle="FullWidth">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell IsEnabled="{Binding IsEnabled, UpdateSourceEventName=ValueChanged, Mode=TwoWay, Converter={StaticResource DebugConverter}}">
<Templates:SettingTemplate/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
</Grid>
Take note of the PeripheralDetailsTemplate:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="75"/>
</Grid.ColumnDefinitions>
<!--Icon-->
<Frame Padding="5">
<Images:VectorImage ResourceId="{Binding HardwareType, Converter={StaticResource hardwareTypeToSVGPathConverter}}"
WidthRequest="150" HeightRequest="150"
HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<Frame>
<Label Text="{Binding Name, FallbackValue=Peripheral Name}" FontSize="Medium" FontAttributes="Bold" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="1">
<Label Text="{Binding HardwareType, FallbackValue=Peripheral Type}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="2">
<Label Text="{Binding MacAddress, StringFormat='Mac: {0}', FallbackValue=000111222333}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
<Frame Grid.Row="3">
<Label Text="{Binding FirmwareRevision, StringFormat='Firmware: {0}', FallbackValue=01AB}" FontSize="Micro" HorizontalOptions="Start" VerticalOptions="Center"/>
</Frame>
</Grid>
<Frame Grid.Column="2">
<Label Text="Conn" HorizontalOptions="Center" VerticalOptions="Center" TextColor="{Binding IsConnected, Converter={StaticResource BoolToColorConverter}, FallbackValue={StaticResource LynkdBlue}}"/>
</Frame>
</Grid>
It is bound to EXACTLY THE SAME PROPERTY AS THE ViewCell!!! and it works fine. I'm looking for the difference and haven't found it yet. I just know that I have properly set the bindingcontext because it databinds once and I know I'm properly firing NotifyPropertyChanged because the other template which is bound to the same property updates as I would expect. I have attached a debugconverter and it is never run. I think it's interesting that in both situations I was working with a ViewCell. These are two separate code bases with the same issue. :/
Simple answer; I was binding to a read-only property in my model that was based off of another property. When the other property changed I was not firing OnPropertyChanged for the read-only property.

Xaml ResourceKey as a variable not working

I'm using a ComboBox (WPF 4.0) to show user defined paragraph styles for an editor app. The ComboBox has two columns:
(1) Name of the paragraph style
(2) Text "abcABC123", should in some properties be formatted according to the paragraph style in the first column
(1) is working, (2) is not because _ResourceKey_background, _ResourceKey_foreground and _ResourceKey_fontFamily are no ResourceKeys
but variables containing ResourceKeys. How can I solve this?
_NameInternal, _NameUI, _ResourceKey_background, _ResourceKey_foreground and _ResourceKey_fontFamily are public properties
of the user defined paragraph style class.
<ComboBox Name="_cbStylesPara" SelectedValuePath="_NameInternal"
ItemsSource="{Binding Source={StaticResource _collectionViewSource_stylesPara}}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="{Binding _NameUI}" VerticalAlignment="Center" />
<TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0" VerticalAlignment="Center"
Background="{DynamicResource _ResourceKey_background}"
Foreground="{DynamicResource _ResourceKey_foreground}"
FontFamily="{DynamicResource _ResourceKey_fontFamily}" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
As like you said resources are declared under App resources, what you can do is create an IValueConverter and return the resource value from it's Convert method.
public class ResouceLookupConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return App.Current.TryFindResource(value);
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
return Binding.DoNothing;
}
}
XAML:
<ComboBox>
<ComboBox.Resources>
<local:ResouceLookupConverter x:Key="ResouceLookupConverter"/>
</ComboBox.Resources>
......
<TextBlock Grid.Column="1" Text="abcABC123" Margin="3,0,0,0"
VerticalAlignment="Center"
Background="{Binding _ResourceKey_background,
Converter={StaticResource ResouceLookupConverter}}"
Foreground="{Binding _ResourceKey_foreground,
Converter={StaticResource ResouceLookupConverter}}"
FontFamily="{Binding _ResourceKey_fontFamily,
Converter={StaticResource ResouceLookupConverter}}" />
</ComboBox>
Note: Ofcourse you have to define local namespace in your XAML set to the namespace where your Converter is declared.

Categories

Resources