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
Related
I am currently working on a Xamarin CrossPlatform project and have implemented a Listview bound to an ObservableCollection. Everything works out fine until I remove an Item from the ListView. The images in the follow up items within the ListView disappear randomly - not all of them and a different amount of them every time. I guess it has something to do with the MemoryStream, but what do I have to change? Here´s the relevant part of my Model that is bound to the ListView:
public string ImageBase64
{
get
{
return imagebase64;
}
set
{
if (imagebase64 != value)
{
imagebase64 = value;
OnPropertyChanged(nameof(ImageBase64));
OnPropertyChanged(nameof(ImageSource));
}
}
}
public ImageSource ImageSource
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(Convert.FromBase64String(imagebase64)));
}
else
{
return null;
}
}
}
Here´s the relevant XAML:
<ListView x:Name="listView" Margin="20" ItemsSource="{Binding}" ItemSelected="OnListItemSelected" HasUnevenRows="True" SeparatorColor="{StaticResource primaryGreen}" SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Margin="0,5,0,5">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Grid.RowSpan="3" Margin="-2,-2,-2,-2" Source="{Binding ImageSource}" HorizontalOptions="Start" VerticalOptions="Center" Aspect="AspectFill"/> <!-- This is the displayed Image -->
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="0" FontAttributes="Bold" FontSize="18" TextColor="{StaticResource primaryGreen}" Text="{Binding VorNachname}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<Label Margin="10,0,0,0" Grid.Column="1" Grid.Row="1" Text="{Binding MediumSelected.Wert, StringFormat='via {0}'}" HorizontalOptions="FillAndExpand" VerticalTextAlignment="Start" HorizontalTextAlignment="Start"/>
<StackLayout Margin="10,0,0,0" Grid.Column="1" Grid.Row="2" Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Alter,StringFormat='Alter: {0}'}" VerticalTextAlignment="Start" HorizontalTextAlignment="Start" HorizontalOptions="Start"/>
</StackLayout>
<StackLayout Margin="0,0,0,-5" Grid.Column="2" Grid.RowSpan="3" Orientation="Vertical" HorizontalOptions="End" VerticalOptions="End">
<Button WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderWidth="0" BorderColor="White" Image="socialmedia_18.png" Clicked="OnChangeClicked" CommandParameter ="{Binding}" VerticalOptions="EndAndExpand" />
<Button Margin="0,-15,0,0" WidthRequest="40" HeightRequest="40" BackgroundColor="White" BorderColor="White" Image="cancel_18.png" Clicked="OnDeleteClicked" CommandParameter ="{Binding}" VerticalOptions="End" />
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
...and the Code behind:
async void OnDeleteClicked(object sender, EventArgs e)
{
Helper.TrackEvent("PeopleList_OnDeleteClicked");
//Get selected Person
Person person = (Person)((Button)sender).CommandParameter;
//Remove from Model
DBHelper.DBModel.People.Remove(person);
//Update database
App.Database.UpdateWithChildren(DBHelper.DBModel);
}
EDIT:
Resizing the images does not help, same problem. I tried it by binding a testvariable ImageSourceThumb to the ListViewItemImage:
public ImageSource ImageSourceThumb
{
get
{
if (!string.IsNullOrEmpty(imagebase64))
{
return ImageSource.FromStream(() => new MemoryStream(ImageResizer.ResizeImage(Convert.FromBase64String(imagebase64), 64, 64)));
}
else
{
return null;
}
}
}
I had a similar problem. When I loaded or updated my listview not all the images showed up.
I fixed my problem resizing the images. Huge images gived me a outofmemory exception. Resizing those images to a smaller resolution fixed these problems.
I am trying to implement my own lockscreen in my xamarin app. I have created the numpad as below:
<ContentPage.Content>
<Grid Padding="0,0,0,10">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Image Grid.Row="0" Source="alpaca.png" />
<Label Grid.Row="1" Text="{Binding PincodeMasked}" FontFamily="Lato-Bold" TextColor="Black" VerticalOptions="Center" FontSize="80" HorizontalTextAlignment="Center" />
<Grid Grid.Row="2" Padding="40,0,30,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Image="num1.png" Command="{Binding NumberCommand}" CommandParameter="1" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="0" Grid.Column="1" Image="num2.png" Command="{Binding NumberCommand}" CommandParameter="2" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="0" Grid.Column="2" Image="num3.png" Command="{Binding NumberCommand}" CommandParameter="3" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="1" Grid.Column="0" Image="num4.png" Command="{Binding NumberCommand}" CommandParameter="4" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="1" Grid.Column="1" Image="num5.png" Command="{Binding NumberCommand}" CommandParameter="5" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="1" Grid.Column="2" Image="num6.png" Command="{Binding NumberCommand}" CommandParameter="6" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="2" Grid.Column="0" Image="num7.png" Command="{Binding NumberCommand}" CommandParameter="7" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="2" Grid.Column="1" Image="num8.png" Command="{Binding NumberCommand}" CommandParameter="8" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="2" Grid.Column="2" Image="num9.png" Command="{Binding NumberCommand}" CommandParameter="9" BackgroundColor="#00FFFFFF" />
<Button Grid.Row="3" Grid.Column="1" Image="num0.png" Command="{Binding NumberCommand}" CommandParameter="0" BackgroundColor="#00FFFFFF" />
</Grid>
</Grid>
</ContentPage.Content>
In the ViewModel I want to do something like this
public PinLoginPageModel()
{
NumberCommand = new Command(NumpadToNumber);
}
void NumpadToNumber(object obj)
{
if(Button.CommandParameter == 0)
{
PincodeMasked = "0";
}
}
I want to convert each button click to a corresponding value, however I am getting an error at Button.CommandParameter saying it needs to have an object reference. How can I reference this to the button in the XAML code?
Thanks
You need to change your view mode code like below:
public PinLoginPageModel()
{
NumberCommand = new Command<string>(NumpadToNumber);
}
void NumpadToNumber(string obj)
{
if(obj == "0")
{
PincodeMasked = "0";
}
}
Try this:
void NumpadToNumber(object parameter)
{
if (parameter != null && parameter.ToString() == "0")
{
PincodeMasked = "0";
}
}
Just change your view model like this:
public PinLoginPageModel()
{
NumberCommand = new Command<object>(NumpadToNumber);
}
void NumpadToNumber(object obj)
{
if((obj as int) == 0)
PincodeMasked = "0";/
}
I will be able to deselect my item when i click second time on it.
When I tap an item the background color changed to blue. I want that the background gets the default color when I tap second time to the same item from the list.
Here can you find my code but it isn't working.
XAML
<StackLayout Margin="5,0,5,0" HorizontalOptions="FillAndExpand" VerticalOptions="CenterAndExpand">
<Frame Style="{StaticResource StandardFrameStyle}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<ListView x:Name="lst_pickList" ItemSelected="OnItemSelected" ItemTapped="OnItemTapped" ItemsSource="{Binding PickList}" HasUnevenRows="True" Style="{StaticResource StandardListViewStyle}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid x:Name="grd_pickList" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label x:Name="lbl_comment" Text="Comment:" FontAttributes="Bold" Grid.Row="0" Grid.Column="0" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_itemNo" Text="ItemNo:" FontAttributes="Bold" Grid.Row="0" Grid.Column="2" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_description" Text="Description:" FontAttributes="Bold" Grid.Row="1" Grid.Column="0" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_restant" Text="Restant:" FontAttributes="Bold" Grid.Row="1" Grid.Column="2" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_comment_binding" Text="{Binding Comment}" Grid.Row="0" Grid.Column="1" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_itemNo_binding" Text="{Binding ItemNo}" Grid.Row="0" Grid.Column="3" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_description_binding" Text="{Binding Description}" Grid.Row="1" Grid.Column="1" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
<Label x:Name="lbl_restant_binding" Text="{Binding Restant}" Grid.Row="1" Grid.Column="3" VerticalTextAlignment="Center" Style="{StaticResource StandardLabelStyle}" />
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Frame>
</StackLayout>
CodeBehind
public void OnItemTapped(object sender, ItemTappedEventArgs args)
{
var newSelectedPick = args.Item as Pick;
if(selectedPick != null && selectedPick.Id == newSelectedPick.Id)
{
lst_pickList.SelectedItem = null;
}
else
{
selectedPick = newSelectedPick;
}
}
Create a boolean property on your Pick object named IsSelected ,then Bind it your grd_pickList's BackgroundColor with a converter.
i.e:
//Xaml
<ListView.Resources>
<ResourceDictionary>
<local:BgConverter x:Key="BgConverter"/>
</ResourceDictionary>
</ListView.Resources>
<Grid x:Name="grd_pickList" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" BackgroundColor="{Binding IsSelected,Converter={StaticResource BgConverter}}" >
//Converter
class BgConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool &&(bool)value)
return Color.Blue;
else
return Color.White;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
//Xaml.cs
public void OnItemTapped(object sender, ItemTappedEventArgs args)
{
var itm = args.Item as Pick;
itm.IsSelected = !itm.IsSelected;
}
Important: Be Sure IsSelected Property Triggers OnPropertyChanged event.
I want to assign the values of the findFamily object to the different TextBox(s) i tried the following code but it's not working would you please suggest me a better way. Thanks in advance.
private void Search_Click(object sender, RoutedEventArgs e)
{
if (SearchFamilyMemberId.Text.Trim() != "")
{
SITDataDataContext con = new SITDataDataContext();
List<Family> findFamily = (from s in con.Families where s.FamilyMemberId.Equals(SearchFamilyMemberId.Text.Trim()) select s).ToList();
if (findFamily.Any())
{
FamilyMemberId.Text = findFamily[0];
FirstName.Text = findFamily[1];
LastName.Text = findFamily[2];
if (findFamily[3]=="Male")
{
Male.IsChecked = true;
}
else
{
Female.IsChecked = true;
}
Phone.Text = findFamily[4];
Address.Text = findFamily[5];
}
else
{
MessageBox.Show("Family Id not found!");
}
}
else
{
MessageBox.Show("Invalid Id!");
}
}
here is my xamal code
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="1" Grid.Column="0" Content="Family Member ID:"/>
<Label Grid.Row="2" Grid.Column="0" Content="First Name:"/>
<Label Grid.Row="3" Grid.Column="0" Content="Last Name:"/>
<Label Grid.Row="4" Grid.Column="0" Content="Gender:"/>
<Label Grid.Row="5" Grid.Column="0" Content="Phone:"/>
<Label Grid.Row="6" Grid.Column="0" Content="Address:"/>
<CheckBox Name="ColonyResident" Content="Colony Resident" Grid.Row="0" Grid.Column="0" Margin="5" Checked="ColonyResident_Checked" Unchecked="ColonyResident_Unchecked"/>
<TextBox Name="SearchFamilyMemberId" IsEnabled="False" SelectionChanged="FamilyMemberId_SelectionChanged" Grid.Row="0" Grid.Column="1" Margin="3"/>
<TextBox Name="FamilyMemberId" IsEnabled="False" Grid.Row="1" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="FirstName" Grid.Row="2" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="LastName" Grid.Row="3" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<RadioButton Name="Male" Grid.Row="4" Grid.Column="1" Margin="3" Content="Male" />
<RadioButton Name="Female" Grid.Row="4" Grid.Column="2" Margin="3" Content="Female" />
<TextBox Name="Phone" Grid.Row="5" Grid.Column="1" Margin="3" Grid.ColumnSpan="2"/>
<TextBox Name="Address" Grid.Row="6" Grid.Column="1" Margin="3" Grid.ColumnSpan="2" TextWrapping="Wrap"/>
<Button Name="Search" IsEnabled="False" Grid.Row="0" Grid.Column="2" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Search" Click="Search_Click"/>
<Button IsDefault="True" Grid.Row="7" Grid.Column="1" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Add" Click="Add_Click"/>
<Button Grid.Row="7" Grid.Column="2" Margin="3" MinWidth="100" MinHeight="25" HorizontalAlignment="Center" Content="Clear" Click="Clear_Click"/>
</Grid>
Why don't you use data binding?
For each of the text boxes that you have, bind your TextBox.Text to its corresponding property in the view model, something like this:
<TextBox Text={Binding FirstName} />
Then, assign your FirstName, LastName...etc. properties to values and raise INotifyPropertyChanged.PropertyChanged for each of the properties (your view model should implement INotifyPropertyChanged) and your view (i.e. UI) should get updated.
I don't agree with any of the answers posted here. The question doesn't seem to be correct.
If you have a list of Family members. Then how can you show it as a single item. How do you know which item you want to display.
Hence my suggestion is to use a listbox and using data binding, create a view to display the current selected Family member's data in that view.
use foreach loop through list as:
foreach(var a in findFamily)
{
txtbox.text=a[0].tostring();
txtbox2.text=a[1].tostring();
}
or use:
txtbox.text = findFamily.Select(a => a[0].ToString()).FirstOrDefault().ToString();
I have the following:
<DockPanel Height="25" HorizontalAlignment="Stretch">
<Button Content="Add" x:Name="bAdd" DockPanel.Dock="Left" />
<Button Content="Remove" x:Name="bRemove" DockPanel.Dock="Right" />
</DockPanel>
Can someone suggest me how to make both the buttons have equal width without setting the Width property of the buttons manually?
If you absolutely don't want to set the Width propety, you can just use a Grid :
<Grid Height="25" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Content="Add" x:Name="bAdd" />
<Button Grid.Column="1" Content="Remove" x:Name="bRemove" />
</Grid>
They will both have the same Width this way
<UniformGrid Columns="2">
<Button Content="Ok" Grid.Column="0"/>
<Button Content="Cancel" Grid.Column="1"/>
</UniformGrid>
In addition to the #Amir's answer you can control the numbers of buttons dynamically by binding Visbility.
<UniformGrid Rows="1">
<Button Content="Ok" Visiblity="{Binding IsShowOkayButton, Converter={...}"/>
<Button Content="Cancel" Visiblity="{Binding IsShowCancelButton, Converter={...}}"/>
</UniformGrid>
Use with enumeration:
(Assuming that ConfirmType and IsShowCancelButton in the same ViewModel)
public enum ConfirmType { Confirm, ConfirmOrCancel }
public ConfirmType ConfirmType { get => _ConfirmType;
set {
switch (_ConfirmType)
{
case ConfirmType.Confirm:
IsShowCancelButton = false;
break;
case ConfirmType.ConfirmOrCancel:
IsShowCancelButton = true;
break;
}
// Your RaisePropertyChanged code here
}
}