How to bind the data from code inside XAML - xaml

I have this class:
public partial class Calendar : ContentPage, INotifyPropertyChanged
{
public ICommand EventSelectedCommand => new Command(async (item) => await ExecuteEventSelectedCommand(item));
public ICommand DayTappedCommand => new Command<DateTime>(async (date) => await DayTapped(date));
public EventCollection Events { get; set; }
private void SetCalendar()
{
Events = new EventCollection
{
[DateTime.Now] = new List<EventModel>
{
new EventModel { Name = "Herrenabend, 10:00 - 12:00 – 5000 Scanns", ID = 100},
};
}
and I wanna do bind the data to my calendar.
I tried this:
<Grid Grid.Row="1" Grid.Column="1">
<controls:Calendar
x:Name="calender"
DayTappedCommand="{Binding DayTappedCommand}"
Events="{Binding Q2go.MainMenu_Partners.Calendar.Events}">
<controls:Calendar.EventTemplate>
<DataTemplate>
<StackLayout>
<Label
Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Medium" >
<Label.GestureRecognizers>
<TapGestureRecognizer
Tapped="ClickOnLabel"
/>
</Label.GestureRecognizers>
</Label>
<Label
Grid.Row="1"
Text="{Binding ID}"
FontSize="8" >
<Label.GestureRecognizers>
<TapGestureRecognizer
Tapped="ClickOnLabel"
/>
</Label.GestureRecognizers>
</Label>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding BindingContext.EventSelectedCommand, Source={x:Reference test}}"
CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</controls:Calendar.EventTemplate>
</controls:Calendar>
</Grid>
But the data isn't given into the calendar and non of the events fire.
Where is the missing link here?
I thought by: Events="{Binding Q2go.MainMenu_Partners.Calendar.Events}">
I am doing everything correctly. but nothing is displayed. Why is that?
I know that if I just give the data to the calendar inside code (calender.events = events) it works just fine (still no event handlers) but i want it to bind the data from code. So without this line (calender.events = events).
I read in every sample that this should work, but it doesn't for me. So where is the issue?

if your page's BindingContext is set to this then you should just use Events="{Binding Events}" as the Binding expression

Related

How to bind properties for a custom user control properly in avalonia ui

I am trying to display a text on a custome user control. I want that text to be passed via a mainview
this is the code I have:
MainView.axaml
<cc:Slot Grid.Row="0" Grid.Column="1" Dot="Number one"/>
<cc:Slot Grid.Row="0" Grid.Column="2" Dot="Number two"/>
This is my custom user control:
Slot.axaml
<UserControl xmlns="https://github.com/avaloniaui"
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:controls="clr-namespace:Avalonia.Controls;assembly=Avalonia.Controls"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
xmlns:cc="clr-namespace:Diagnostica.CustomControls;assembly=Diagnostica.CustomControls"
x:Class="Diagnostica.CustomControls.OmniSlot">
<Button>
<TextBlock Text="{Binding Dot}"/>
</Button>
</Grid>
</Button>
</UserControl>
and its .cs file"
Slot.axaml.cs
public string Dot
{
get => GetValue(DotProperty);
set => SetValue(DotProperty, value);
}
public static readonly StyledProperty<string> DotProperty =
AvaloniaProperty.Register<Slot, string>(nameof(Dot), defaultValue: "Black");
what i get like this is a disabled box. How can this get fixed?
View:
<Rectangle Stroke="{TemplateBinding DotColor}" StrokeThickness="2" Width="20" Height="20" Fill="{TemplateBinding DotColorBrush}" VerticalAlignment="Top" HorizontalAlignment="Right"/>
ViewModel:
public static readonly StyledProperty<string> DotColorProperty = AvaloniaProperty.Register<OmniSlotControl, string>(nameof(DotColor), "Red");
public string DotColor
{
get => GetValue(DotColorProperty);
set
{
SetValue(DotColorProperty, value);
DotColorBrush = Avalonia.Media.Brush.Parse(value);
}
}

adjust and move the content of a page up slightly when the keyboard appears in an Entry control Xamarin Forms

I have a registration form, when the user is entering data such as Email, below that Entry control there is a Label that appears if there is an error in the input. So my problem is that the virtual keyboard hides the Label showing input errors and I don't want that to happen.
With keyboard.jpg without keyboard.jpg
It will be that there will be some way to move the content of the form a little higher so that the Control Entry can be seen along with the Error Label
<StackLayout>
<Entry
Keyboard="Email"
MaxLength="30"
Placeholder="Enter Email"
ReturnType="Next"
Style="{StaticResource BorderlessEntryStyle}"
Text="{Binding Email.Value}">
<Entry.Behaviors>
<behaviorsValidate:EventToCommandBehavior Command="{Binding ValidateEmailCommand}" EventName="TextChanged" />
</Entry.Behaviors>
</Entry>
<Label
Margin="4,-4,0,0"
FontSize="12"
IsVisible="{Binding Email.IsValid, Converter={StaticResource InverseBoolConverter}}"
Style="{StaticResource SimpleLabelStyle}"
Text="{Binding Email.Errors, Converter={StaticResource FirstValidationErrorConverter}}"
TextColor="{DynamicResource Red}"
VerticalOptions="FillAndExpand" />
</StackLayout>
About adjusting elements when keyboard shows in Xamarin Forms, find one way to do this.
On android you just need to add your elements inside a Grid and use the platform specific UseWindowSoftInputModeAdjust Resize in the Application XAML.
firstly, create a new class that extend from Grid in Shared code.
public class KeyboardView: Grid
{
}
Then adding your control inside it.
<views:KeyboardView Padding="0,60,0,0"
VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="60" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="ic_test"
HeightRequest="80"
WidthRequest="80"
HorizontalOptions="CenterAndExpand"
Grid.Row="0"/>
<Label Text="Login"
FontAttributes="Bold"
TextColor="CornflowerBlue"
HorizontalOptions="CenterAndExpand"
FontSize="25"
VerticalOptions="Center"
Margin="0,20,0,0"
Grid.Row="1"
x:Name="welcomeText"/>
<Entry Placeholder="Email"
Grid.Row="2"
Margin="20,0"
x:Name="email"
ReturnType="Done"
Keyboard="Email"/>
<Entry Placeholder="Password"
Margin="20,0"
Grid.Row="3"
HeightRequest="50"
x:Name="password"
ReturnType="Done"
IsPassword="true"/>
<Button VerticalOptions="EndAndExpand"
BackgroundColor="CornflowerBlue"
HeightRequest="60"
TextColor="White"
CornerRadius="0"
Grid.Row="4"
Text="Login"/>
</views:KeyboardView>
Thirdly, add platform specific UseWindowSoftInputModeAdjust with Resize value on the Application XAML
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="KeyboardSample.App"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:Application.WindowSoftInputModeAdjust="Resize">
On iOS we have to create a custom renderer to do the resize. Don't test on ios device.
[assembly: ExportRenderer(typeof(KeyboardView), typeof(KeyboardViewRenderer))]
namespace KeyboardSample.iOS.Renderers
{
public class KeyboardViewRenderer : ViewRenderer
{
NSObject _keyboardShowObserver;
NSObject _keyboardHideObserver;
protected override void OnElementChanged(ElementChangedEventArgs<View> e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
RegisterForKeyboardNotifications();
}
if (e.OldElement != null)
{
UnregisterForKeyboardNotifications();
}
}
void RegisterForKeyboardNotifications()
{
if (_keyboardShowObserver == null)
_keyboardShowObserver = UIKeyboard.Notifications.ObserveWillShow(OnKeyboardShow);
if (_keyboardHideObserver == null)
_keyboardHideObserver = UIKeyboard.Notifications.ObserveWillHide(OnKeyboardHide);
}
void OnKeyboardShow(object sender, UIKeyboardEventArgs args)
{
NSValue result = (NSValue)args.Notification.UserInfo.ObjectForKey(new NSString(UIKeyboard.FrameEndUserInfoKey));
CGSize keyboardSize = result.RectangleFValue.Size;
if (Element != null)
{
Element.Margin = new Thickness(0, 0, 0, keyboardSize.Height); //push the entry up to keyboard height when keyboard is activated
}
}
void OnKeyboardHide(object sender, UIKeyboardEventArgs args)
{
if (Element != null)
{
Element.Margin = new Thickness(0); //set the margins to zero when keyboard is dismissed
}
}
void UnregisterForKeyboardNotifications()
{
if (_keyboardShowObserver != null)
{
_keyboardShowObserver.Dispose();
_keyboardShowObserver = null;
}
if (_keyboardHideObserver != null)
{
_keyboardHideObserver.Dispose();
_keyboardHideObserver = null;
}
}
}
}

Binding IsVisible to property toggled by Switch

I have a Switch bound to a property of an element in a List. I want to bind IsVisible of a button to the same property, but the button's visibility is not changed when the property is changed by the Switch. What am I missing?
XAML:
<StackLayout>
<ListView HorizontalOptions="FillAndExpand" ItemsSource="{Binding EquipmentList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" />
<Switch IsToggled="{Binding State}" />
<Button
Command="{Binding BindingContext.DoCommand, Source={x:Reference TestPage}}"
CommandParameter="{Binding .}"
IsVisible="{Binding State}"
Text="Click" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
ViewModel:
private Command<Equipment> _doCommand;
public Command<Equipment> DoCommand => _doCommand ??
(_doCommand = new Command<Equipment>((Equipment obj) => HandleEquipment(obj)));
// Outputs correct Name and State of the list item
private void HandleEquipment(Equipment obj)
{
System.Diagnostics.Debug.WriteLine(obj.Name + ", " + obj.State);
}
Model:
class Equipment
{
public int Id { get; set; }
public string Name { get; set; }
public bool State { get; set; }
public Equipment(int Id, string Name, bool State)
{
this.Id = Id;
this.Name = Name;
this.State = State;
}
}
As Gerald wrote in his first comment: You have to implement the INotifyPropertyChanged interface on your Equipment model (and not just in the ViewModel).
Without this implementation, the elements in the view have no chance to know, that the state changed (in your case the button).
Implementation:
public class Equipment: INotifyPropertyChanged
{
public bool State
{
get => _state;
set =>
{
_state = value;
OnPropertyChanged();
}
}
private bool _state;
// OTHER PROPERTIES
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The call of the method OnPropertyChanged() is important. The IsVisible property of the button recognizes the change and updates his value.
Instead of binding two things to a property, why not have the single item bound (i.e. the switch) and use XAML to show or hide the button:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
</Window.Resources>
<StackLayout>
<ListView HorizontalOptions="FillAndExpand" ItemsSource="{Binding EquipmentList}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Name}" />
<Switch Name="toggleSwitch" IsToggled="{Binding State}" />
<Button
Command="{Binding BindingContext.DoCommand, Source={x:Reference TestPage}}"
CommandParameter="{Binding .}"
IsVisible="{Binding ElementName=toggleSwitch, Path=IsToggled, Converter={StaticResource BooleanToVisibilityConverter}"
Text="Click" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
It may not be a Window that your StackLayout is in, but if you place a BooleanToVisibilityConverter in your Resources section you'll then be able to use it in your XAML file.
This will mean that if the property name changes in the future you only have one place you need to update in the user interface and you're also using the power of the XAML language.
Also as correctly pointed out by everyone, you need to implement INotifyPropertyChanged in the model in order for the Switch to be updated too.

Xamrin Forms : Swipe to delete(gesture) in ListView

I want to implement the swipe to delete functionality in Xamrin Forms, for which i have tried the following.
Wrote a custom renderer for the list view and in the "OnElementChanged" of the renderer am able to access the binded command to the "CustomListView" and am able to add this command to the Swipe Gesture as added below.
swipeGestureRecognizer = new UISwipeGestureRecognizer (() => {
if (command == null) {
Console.WriteLine ("No command set");
return;}
command.Execute (null);
});
However i am having trouble in accessing the specific row(swiped row), so that i could make a button visible/hidden on the swiped row in the list view. Please could you recommend a way to implement the same?
Swipe to delete is now built into Xamarin Froms ListViews using a ContextAction. Here is the most basic tutorial of how to do it. It is very easy to implement.
http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/listview/
You could do something like this:
protected override void OnElementChanged (ElementChangedEventArgs<ListView> e)
{
base.OnElementChanged (e);
var swipeDelegate = new SwipeRecogniserDelegate ();
swipeGestureRecognizer = new UISwipeGestureRecognizer {
Direction = UISwipeGestureRecognizerDirection.Left,
Delegate = swipeDelegate
};
swipeGestureRecognizer.AddTarget (o => {
var startPoint = swipeDelegate.GetStartPoint ();
Console.WriteLine (startPoint);
var indexPath = this.Control.IndexPathForRowAtPoint(startPoint);
if(listView.SwipeCommand != null) {
listView.SwipeCommand.Execute(indexPath.Row);
}
});
this.Control.AddGestureRecognizer (swipeGestureRecognizer);
this.listView = (SwipableListView)this.Element;
}
The key is SwipeRecogniserDelegate. its implemented like so:
public class SwipeRecogniserDelegate : UIGestureRecognizerDelegate
{
PointF startPoint;
public override bool ShouldReceiveTouch (UIGestureRecognizer recognizer, UITouch touch)
{
return true;
}
public override bool ShouldBegin (UIGestureRecognizer recognizer)
{
var swipeGesture = ((UISwipeGestureRecognizer)recognizer);
this.startPoint = swipeGesture.LocationOfTouch (0, swipeGesture.View);
return true;
}
public PointF GetStartPoint ()
{
return startPoint;
}
}
I was able to accomplish this with the new Xamarin.Forms
SwipeView
Pass the current row into the CommandParameter, and use it in the event handler.
FYI: For some reason the SwipeView has a default BackgroundColor of white, which you can override with something else to match your theme.
Xaml:
<ListView Margin="-20,0,0,0" x:Name="photosListView" ItemSelected="OnItemSelected" VerticalOptions="FillAndExpand" SeparatorColor="Gray" VerticalScrollBarVisibility="Default" HasUnevenRows="true" SeparatorVisibility="Default" Background="{StaticResource PrimaryDark}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<SwipeView BackgroundColor="{StaticResource PrimaryDark}" >
<SwipeView.RightItems>
<SwipeItems>
<SwipeItem Text="Delete" BackgroundColor="LightPink" Clicked="OnDeleteRow" CommandParameter="{Binding .}" />
</SwipeItems>
</SwipeView.RightItems>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackLayout Orientation="Horizontal">
<CheckBox IsVisible="{Binding SelectEnabled}" Color="{StaticResource White}" IsChecked="{Binding Selected}" Margin="20,0,-15,0" CheckedChanged="OnItemCheckedChanged" />
<Grid WidthRequest="70" HeightRequest="50">
<Grid.Margin>
<OnPlatform x:TypeArguments="Thickness" Android="15,0,0,0" iOS="10,0,0,0" />
</Grid.Margin>
<Image Aspect="AspectFill" Source="{Binding ThumbImageSource}" HorizontalOptions="Fill" />
</Grid>
</StackLayout>
<StackLayout Grid.Column="1" Spacing="0" Padding="0" Margin="0,5,0,0">
<Label Text="{Binding Photo.Description}" TextColor="{StaticResource TextColour}" FontSize="16" FontAttributes="Bold" />
<Label Text="{Binding DateTakenString}" TextColor="{StaticResource TextColour}" FontSize="14" />
</StackLayout>
</Grid>
</SwipeView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
cs:
public async void OnDeleteRow(object sender, EventArgs e)
{
if (await GetDeleteRowConfirmationFromUser())
{
SwipeItem si = sender as SwipeItem;
PhotoListItem itemToDelete = si.CommandParameter as PhotoListItem;
LocalDatabaseService db = new LocalDatabaseService();
db.DeletePhoto(itemToDelete.Photo);
_listItems.Remove(itemToDelete);
}
}

How to call command inside listbox in silverlight4

I am using Listbox and it contains button ,and i want to handle button click event using command.but my command never calls.
is this Correct way??
<pmControls:pmListBox Grid.Row="1" Margin="3" ItemsSource="{Binding Countries}" SelectedItem="{Binding SelectedCountry}" >
<pmControls:pmListBox.ItemTemplate >
<DataTemplate >
<Button Command="{Binding GetAllStatesCommand}" CommandParameter="{Binding}" Margin="3" Width="100" Height="50" Content="{Binding Title}">
</Button>
</DataTemplate>
</pmControls:pmListBox.ItemTemplate>
</pmControls:pmListBox>
The DataContext of one list item is different from the DataContextof the surrounding control. To bind that command to the DataContext of that control you have two options:
Either you provide the control with a name and reference to that:
<pmControls:pmListBox x:Name="myCoolListBox" [...]>
<pmControls:pmListBox.ItemTemplate>
<DataTemplate>
<Button Command="{Binding DataContext.GetAllStatesCommand, ElementName=myCoolListBox}" CommandParameter="{Binding}" [...] />
</DataTemplate>
</pmControls:pmListBox.ItemTemplate>
</pmControls:pmListBox>
Or you create class holding your DataContext...
public class DataContextBinder : DependencyObject
{
public static readonly DependencyProperty ContextProperty = DependencyProperty.Register("Context", typeof(object), typeof(DataContextBinder), new PropertyMetadata(null));
public object Context
{
get { return GetValue(ContextProperty); }
set { SetValue(ContextProperty, value); }
}
}
...and create an instance of that in the resources section of your ListBox:
<pmControls:pmListBox x:Name="myCoolListBox" [...]>
<pmControls:pmListBox.Resources>
<local:DataContextBinder x:Key="dataContextBinder" Context="{Binding}" />
</pmControls:pmListBox.Resources>
<pmControls:pmListBox.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Context.GetAllStatesCommand, Source={StaticResource dataContextBinder}" CommandParameter="{Binding}" [...] />
</DataTemplate>
</pmControls:pmListBox.ItemTemplate>
</pmControls:pmListBox>