The Resource 'ImageConverter' could not be resolved - c#

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

Related

XAML/WPF Binding to Page.Resources - How does binding flow?

I am attempting to use 2 DataTemplates to create something like this below:
I need a control that will allow for my dynamically built name-tags (chips per Material Design in XAML) to populate the blue boxed area stacking horizontally first then stacking vertically as each row fills up. Per my understanding a WrapPanel is what I need to use, I've found various examples and have attempted adapting them to fit my needs. I think I'm dang close with this one, but can't figure out what I'm missing here.
Per my understanding My ScrollViewer.ItemsControl should bring in my x:Key="Recipients" DataTemplate which should implement my x:Key="RecipientChip"DataTemplate for as many instances of Patient are in my IEnumerable<Patient> set called Patients.
I don't think I'm binding things correctly though because when I build, I see nothing printed. It's not throwing any errors in my output tab though so I'm not sure what's going on. My Patients IEnumeral is filled like an indexed object as expected. Can someone help me understand why my chips aren't showing up and how the flow of the bindings go? I feel like I'm passing Patients through my ScrollViewer.ItemsControll to the referenced Controls but maybe I'm just reading into this too much?
Here's my code:
XAML
<Page.Resources>
<DataTemplate x:Key="RecipientChip">
<StackPanel>
<materialDesign:Chip
Content="{Binding Patient.Name}">
<materialDesign:Chip.Icon>
<Image
Source="{Binding Patient.Image}" />
</materialDesign:Chip.Icon>
</materialDesign:Chip>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="Recipients">
<StackPanel>
<Label Content="Recipients:" Background="Gray" FontSize="16" />
<ItemsControl x:Name="Recipients" ItemsSource="{Binding Patients}" ItemTemplate="{StaticResource RecipientChip}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32*"/>
<ColumnDefinition Width="126*"/>
<ColumnDefinition Width="Auto" MinWidth="66.999"/>
<ColumnDefinition Width="193*"/>
<ColumnDefinition Width="32*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<materialDesign:Card
Background="{DynamicResource PrimaryHueLightBrush}"
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
Grid.ColumnSpan="3"
Padding="8"
Margin="0,65,0,50">
<StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ItemsControl ItemTemplate="{StaticResource Recipients}" />
</ScrollViewer>
</StackPanel>
</materialDesign:Card>
Code Behind:
public partial class EmailMessageView : Page
{
public EmailMessageView(Email email)
{
InitializeComponent();
Email = email;
Patients = email.Patients.Data;
EmailContent.NavigateToString(email.Content);
}
public Email Email;
public IEnumerable<Patient> Patients;
}
Patients
-[0] {Mable} NotificationLinkApp.Models.Patient
Address "9930 Somewhere St. " string
Age 18 double
+ Birthday {NotificationLinkApp.Models.CarbonDate} NotificationLinkApp.Models.CarbonDate
City "Anywhere" string
CommunicationId 3 int?
+ CreatedAt {NotificationLinkApp.Models.CarbonDate} NotificationLinkApp.Models.CarbonDate
Email "Mable.Lang#example.com" string
FirstName "Mable" string
Gender 1 int
HomePhone "555-555-4260" string
HomePhoneIsLandline null int?
Id 1490607 int
Image "pack://application:,,,/Resources/Images/user-unknown.png" string
IsEmail 1 int?
IsMail 1 int?
IsPhone 1 int?
IsReviewRequest 1 int?
IsText 1 int?
LanguageId 25493 int?
LastName "Lang" string
Latitude "40.527834" string
Longitude "-122.318749" string
Name "Mable Lang" string
OfficeId 2 int
ParentId null string
PreferredConfidential "" string
PreferredConfirm "" string
PreferredContact "" string
PreferredRecall "" string
ReferenceId "4634" string
SSN null string
State "New Mexico" string
+ UpdatedAt {NotificationLinkApp.Models.CarbonDate} NotificationLinkApp.Models.CarbonDate
WirelessPhone "555-555-4745" string
WorkPhone "555-555-3226" string
Zip "90134" string
_age 0 double
_email "Mable.Lang#example.com" string
_homePhone "555-555-4260" string
_image "" string
_wirelessPhone "555-555-4745" string
_workPhone "555-555-3226" string
In the end, I was able to get it to work by simplifying the code some as well as setting the DataContext to Patients. I continued to leverage the native functionality of a WrapPanel so that my "chips" would stack horizontally and wrap to a new line much like text. Here is the working code.
XAML
<Page.Resources>
<DataTemplate x:Key="RecipientChip">
<StackPanel>
<materialDesign:Chip
Background="#FFFFFFFF"
Content="{Binding Name}" Click="Chip_Clicked">
<materialDesign:Chip.Icon>
<Image
Source="{Binding Image}" />
</materialDesign:Chip.Icon>
</materialDesign:Chip>
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32*"/>
<ColumnDefinition Width="126*"/>
<ColumnDefinition Width="Auto" MinWidth="66.999"/>
<ColumnDefinition Width="193*"/>
<ColumnDefinition Width="32*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="1*"/>
</Grid.RowDefinitions>
<materialDesign:Card
Background="{DynamicResource PrimaryHueLightBrush}"
Foreground="{DynamicResource PrimaryHueLightForegroundBrush}"
Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
Grid.ColumnSpan="3"
Padding="8"
Margin="0,65,0,50">
<StackPanel>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<StackPanel>
<Label Content="Recipients:" FontSize="16" />
<ItemsControl ItemsSource="{Binding}" ItemTemplate="{StaticResource RecipientChip}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
</ScrollViewer>
</StackPanel>
</materialDesign:Card>
<WebBrowser Name="EmailContent" Grid.Row="1" Grid.Column="1" Grid.RowSpan="5" Grid.ColumnSpan="3" Margin="0,52,0,10"/>
</Grid>
Code Behind
public EmailMessageView(Email email)
{
InitializeComponent();
Email = email;
Patients = email.Patients.Data;
EmailContent.NavigateToString(email.Content);
DataContext = Patients;
}
public Email Email;
public IEnumerable<Patient> Patients;

How to dock listbox to a textbox overlapping other items

I am trying to make textbox with autocomplete drop-down listbox.
The problem lies in that there is not space for listbox, as there are other items just below the textbox. Although, not seen on screenshot, the space between textbox and button will be filled with table.
Is there a way to dock or align a listbox to the bottom of given textbox, regardless to other items in layout?
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="*"/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" x:Name="txtb_name"></TextBox>
<Grid Grid.Row="2" VerticalAlignment="Bottom">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btn_givecancel" Content="Cancel" Height="70" FontSize="18.667" Click="btn_givecancel_Click"/>
<Button Grid.Column="1" x:Name="btn_giveaccept" Content="Accept" Height="70" FontSize="18.667" Click="btn_giveaccept_Click"/>
</Grid>
</Grid>
Here's My Implementation:
Have a Converter that takes Total possible auto suggest item count and current view count:
<local:IntToVisibilityConverter x:Key="IntToVisibilityConverter"/>
Then here's is the Form with TextBox, ListBox and the Button controls.
<Grid Margin="50">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBox Grid.Row="0" Text="{Binding UserText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" DockPanel.Dock="Top"/>
<ListBox Grid.Row="1" Grid.RowSpan="2" VerticalAlignment="Top" MaxHeight="55" ItemsSource="{Binding SuggestionsFiltered, UpdateSourceTrigger=PropertyChanged}"
Canvas.ZIndex="1">
<ListBox.Visibility>
<MultiBinding Converter="{StaticResource IntToVisibilityConverter}">
<Binding Path="MaxCount"/>
<Binding Path="SuggestionsFiltered.Count"/>
</MultiBinding>
</ListBox.Visibility>
</ListBox>
<StackPanel Grid.Row="2" Orientation="Horizontal" Margin="0 50 0 0">
<Button Height="20" Width="100">Clear</Button>
<Button Height="20" Width="100" Margin="10 0 0 0">Accept</Button>
</StackPanel>
</Grid>
Finally, here's my DataContext:
public class TheDataContext
{
public TheDataContext()
{
FillData();
_SuggestionsFiltered = CollectionViewSource.GetDefaultView(_SuggestionSource);
_SuggestionsFiltered.Filter = obj =>
{
var opt = obj as string;
if (string.IsNullOrEmpty(_UserText) || _UserText.Length == 0)
return true;
return string.Join("", opt.Take(_UserText.Length)) == _UserText;
};
}
private void FillData()
{
_SuggestionSource = new List<string>();
_SuggestionSource.Add("Alpha");
_SuggestionSource.Add("Alpines");
_SuggestionSource.Add("Bravo");
_SuggestionSource.Add("Brood");
_SuggestionSource.Add("Charlie");
_SuggestionSource.Add("Charles");
_SuggestionSource.Add("Charlotte");
}
private string _UserText;
public string UserText
{
get => _UserText;
set
{
_UserText = value;
_SuggestionsFiltered.Refresh();
}
}
private List<string> _SuggestionSource;
public int MaxCount => _SuggestionSource.Count;
private ICollectionView _SuggestionsFiltered;
public ICollectionView SuggestionsFiltered
{
get => _SuggestionsFiltered;
}
}
Notice all the code around ICollectionView. Also, I have forcefully set some margins in xaml to show case that Listbox is drawn over other controls (courtsey ZIndex).
If you take this code, remember to handle selected event on ListBox, then set the textBox Text to this value. Also hide the listbox. Bit of a jugglery there.
Lastly, here is the Converter, if you are interested:
public class IntToVisibilityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
int maxCount = System.Convert.ToInt32(values[0]);
int count = System.Convert.ToInt32(values[1]);
if (count > 0 && count != maxCount)
return Visibility.Visible;
return Visibility.Collapsed;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Can't use windowManager.ShowWindow() with Caliburn.Micro

I'm currently developing a plugin for Revit (BIM software) and I'm, trying to use WPF and Caliburn.Micro to show a window/dialog when I press a button of the plugin.
So like in the documentation, I have a bootstrapper:
public class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}
protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<LocationPopupViewModel>();
}
}
}
A simple testing ViewModel:
namespace ExternalForms.ViewModels
{
public class LocationPopupViewModel : Screen
{
private int _horizontalLength;
private int _verticalLength;
public int HorizontalLength
{
get
{
return _horizontalLength;
}
set
{
_horizontalLength = value;
NotifyOfPropertyChange(() => HorizontalLength);
}
}
public int VerticalLength
{
get
{
return _verticalLength;
}
set
{
_verticalLength = value;
NotifyOfPropertyChange(() => VerticalLength);
}
}
}
}
And of course the window that I want to show:
<Window x:Class="ExternalForms.Views.LocationPopupView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ExternalForms.Views"
mc:Ignorable="d" WindowStartupLocation="CenterScreen"
ResizeMode="CanResizeWithGrip"
Title="gebied" Height="300" Width="410"
FontSize="16">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<!--Row 1-->
<TextBlock Text="Stel xxx in" FontWeight="DemiBold" Grid.Column="1" Grid.Row="1" FontSize="18"/>
<!--Row 2-->
<StackPanel Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Width="360" Margin="0, 0, 0, 20">
<TextBlock TextWrapping="Wrap">
Let op dat het gebied een maximale horizontale en verticale lengte mag hebben van 1 kilometer.
</TextBlock>
</StackPanel>
<!--Row 3-->
<TextBlock Text="Horizontaal" Grid.Column="1" Grid.Row="3"/>
<!--Row 4-->
<TextBox x:Name="HorizontalLength" Grid.Row="4" Grid.Column="1" MinWidth="100"/>
<!--Row 5-->
<TextBlock Text="Verticaal" Grid.Column="1" Grid.Row="5"/>
<!--Row 6-->
<TextBox x:Name="VerticalLength" Grid.Row="6" Grid.Column="1" MinWidth="100"/>
<!--Row 7-->
<StackPanel Orientation="Horizontal" Grid.Row="7" Grid.Column="1" Margin="0, 20, 0, 0" Grid.ColumnSpan="2" HorizontalAlignment="Right">
<Button x:Name="SubmitDimensions" IsDefault="True" Width="100" Height="30">OK</Button>
<Button IsCancel="True" IsDefault="True" Width="100" Height="30">Cancel</Button>
</StackPanel>
</Grid>
The function that is trying to show the window:
private void SetBoundingBox()
{
IWindowManager windowManager = new WindowManager();
LocationPopupView locationPopup = new LocationPopupView();
windowManager.ShowWindow(locationPopup, null, null);
}
But when I try to open the dialog in Revit, a window with an error pops up:
UPDATE:
My current project structure looks like this:
Assembly "UI" takes care of all the internal UI elements in Revit (so the buttons in Revit, even though there is currently only one).
The current button in Revit calls the "Get3DBAG" assembly, who does some tasks and eventually calls the "Location" assembly, which calls the Windowmanager.showwindow() method for the WPF views, which are in the "ExternalForms" assembly.
You problem lies in the following line.
LocationPopupView locationPopup = new LocationPopupView();
You are attemping to initialize an instance of View, instead of ViewModel. You should replace this with following.
LocationPopupViewModel locationPopup = new LocationPopupViewModel();
Caliburn Micro would resolve the corresponding View by itself using the naming convention.
Update : Based on Comment
From your comment, it looks like your View/ViewModels are in a different assembly. In that scenario, you need to ensure the assembly is included while Caliburn Micro searches for Views. You can do so by overriding SelectAssemblies method in Bootstrapper.
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
Assembly.GetExecutingAssembly()
// Ensure your external assembly is included.
};
}
You would be also interested to read more Custom Conventions using Caliburn Micro

How to add Parameters in ControlTemplate xamarin forms

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!

Binding to ratio of heights

I'm trying to create a grid with two panes with a grid splitter between them that the user can reposition at runtime. I'd also like to bind a variable representing the ratio of the two panes. I've tried the following XAML:
<local:CustomConverter x:Key="splitPositionConverter2"/>
<StackPanel Margin="10">
<TextBox Name="txtValue" />
<Grid x:Name="splitViewGrid" Height="400">
<Grid.RowDefinitions>
<!--The top panel height is bound to the SplitPosition property. -->
<RowDefinition Height="{Binding ElementName=txtValue, Path=Text, Mode=TwoWay, Converter={StaticResource splitPositionConverter2}}"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Background="Red"/>
<GridSplitter Grid.Row="1"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ResizeDirection="Rows"
Height="15"/>
<Grid Grid.Row="2" Background="Blue"/>
</Grid>
</StackPanel>
And I have the following converter:
public class CustomConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Double db = 0.0;
if (Double.TryParse((string)value, out db))
return new GridLength(db, GridUnitType.Star); // value starts off as 2
else
return new GridLength(1.0, GridUnitType.Star);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is GridLength)
{
GridLength GLen = (GridLength)value;
return GLen.Value.ToString(); // is a very large number
}
return 0;
}
}
So a value of 2 should have the red block to be twice the height of the blue block. The conversion from data to height seems to work but the ConvertBack gives me some weird values. A small nudge will give me a value in ConvertBack of 260* or so.
Am I interpreting this value incorrectly or is there an easier way of doing this?

Categories