I'm trying to only allow one toggle button inside my gridview toggle on. If the next one toggled, the previous toggle button must be de-toggle. the structure of my gridview are these:
GridView bind with an observable collection
Inside a gridview content a user-control represent the gridview item
<controls:AdaptiveGridView.ItemTemplate>
<DataTemplate x:DataType="data:FoodDTO">
<usercontrols:FoodCard FoodId="{x:Bind FoodId}" FoodName="{x:Bind FoodName}" FoodEnglishName="{x:Bind FoodEnglishName}" IsSelected="{Binding IsSelected, Mode=TwoWay}"
MainFoodIcon="{x:Bind MainIcon}" SecondaryFoodIcon="{x:Bind SecondaryIcon}" ToggleClick="FoodCard_ToggleClick"/>
</DataTemplate>
</controls:AdaptiveGridView.ItemTemplate>
Here is the XAML of my User-Control
<Grid Height="130" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Margin="5" Padding="0">
<ToolkitControls:DropShadowPanel x:Name="DropShadowHolder" VerticalAlignment="Stretch" Margin="10" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
BlurRadius="20"
ShadowOpacity="0.5" OffsetX="1" OffsetY="20"
Color="Black">
<Grid Background="{ThemeResource SystemAltHighColor}" Height="100" CornerRadius="5" HorizontalAlignment="Stretch"
VerticalAlignment="Bottom" Padding="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ToggleButton Content="CHỌN" FontWeight="Bold" Click="ToggleButton_Click" IsChecked="{Binding IsSelected, Mode=TwoWay}"
VerticalAlignment="Bottom" Margin="10,0,0,10" Width="70" FontSize="12"/>
<Grid Grid.Column="1" VerticalAlignment="Bottom" Margin="11">
<StackPanel VerticalAlignment="Bottom">
<TextBlock Text="40%" />
<ProgressBar Height="30" CornerRadius="3" Value="40"/>
</StackPanel>
<PersonPicture Width="25" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="0,-10,0,0"/>
</Grid>
<TextBlock Text="{x:Bind FoodName, Mode=OneWay}" Grid.Column="1" Margin="6,0,0,0"
FontSize="15" />
</Grid>
</ToolkitControls:DropShadowPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid Margin="20,0,0,0">
<Image x:Name="MainFoodImage" Width="70" Height="70"
VerticalAlignment="Center" HorizontalAlignment="Center"/>
<Image x:Name="SecondaryFoodImage" Width="20" Height="20"
VerticalAlignment="Top" HorizontalAlignment="Right"/>
</Grid>
<TextBlock Text="{x:Bind FoodEnglishName, Mode=OneWay}" VerticalAlignment="Top" Margin="6,-5,0,0"
FontSize="15" FontWeight="Bold" />
</StackPanel>
Here is the code behind of that UserControl
public sealed partial class FoodCard : UserControl, INotifyPropertyChanged
{
public int FoodId
{
get { return (int)GetValue(FoodIdProperty); }
set { SetValue(FoodIdProperty, value); }
}
// Using a DependencyProperty as the backing store for FoodId. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FoodIdProperty =
DependencyProperty.Register("FoodId", typeof(int), typeof(FoodCard), null);
public string FoodName
{
get { return (string)GetValue(FoodNameProperty); }
set { SetValue(FoodNameProperty, value); }
}
// Using a DependencyProperty as the backing store for FoodName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FoodNameProperty =
DependencyProperty.Register("FoodName", typeof(string), typeof(FoodCard), null);
public string FoodEnglishName
{
get { return (string)GetValue(FoodEnglishNameProperty); }
set { SetValue(FoodEnglishNameProperty, value); }
}
// Using a DependencyProperty as the backing store for FoodEnglishName. This enables animation, styling, binding, etc...
public static readonly DependencyProperty FoodEnglishNameProperty =
DependencyProperty.Register("FoodEnglishName", typeof(string), typeof(FoodCard), null);
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
set {
SetValue(IsSelectedProperty, value);
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsSelected"));
}
}
}
// Using a DependencyProperty as the backing store for IsSelected. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsSelectedProperty =
DependencyProperty.Register("IsSelected", typeof(bool), typeof(FoodCard), new PropertyMetadata(null));
public int MainFoodIcon
{
get { return (int)GetValue(MainFoodIconProperty); }
set
{
SetValue(MainFoodIconProperty, value);
MainFoodImage.Source = new BitmapImage(new Uri(_mainFoods[value]));
}
}
// Using a DependencyProperty as the backing store for MainFoodIcon. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MainFoodIconProperty =
DependencyProperty.Register("MainFoodIcon", typeof(int), typeof(FoodCard), null);
public int? SecondaryFoodIcon
{
get { return (int?)GetValue(SecondaryFoodIconProperty); }
set
{
if(value != null)
{
SetValue(SecondaryFoodIconProperty, value);
SecondaryFoodImage.Source = new BitmapImage(new Uri(_secondaryFoods[value]));
}
else SecondaryFoodImage.Source = null;
}
}
// Using a DependencyProperty as the backing store for SecondaryFoodIcon. This enables animation, styling, binding, etc...
public static readonly DependencyProperty SecondaryFoodIconProperty =
DependencyProperty.Register("SecondaryFoodIcon", typeof(int?), typeof(FoodCard), null);
private readonly IDictionary<int, string> _mainFoods = new Dictionary<int, string>
{
{ 1, "ms-appx:///Assets/FoodAssets/Rice.png"},
{ 2, "ms-appx:///Assets/FoodAssets/Bread.png"},
{ 3, "ms-appx:///Assets/FoodAssets/Spagheti.png"},
{ 4, "ms-appx:///Assets/FoodAssets/Noodle.png"},
{ 5, "ms-appx:///Assets/FoodAssets/LunchFood.png"}
};
private readonly IDictionary<int?, string> _secondaryFoods = new Dictionary<int?, string>
{
{ 6, "ms-appx:///Assets/FoodAssets/Meat.png"},
{ 7, "ms-appx:///Assets/FoodAssets/Chicken.png"},
{ 8, "ms-appx:///Assets/FoodAssets/Egg.png"},
{ 9, "ms-appx:///Assets/FoodAssets/Shrimp.png"},
{ 10, "ms-appx:///Assets/FoodAssets/Falafel.png"}
};
public event FoodCardEventHandler ToggleClick;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public FoodCard()
{
this.InitializeComponent();
}
private void ToggleButton_Click(object sender, RoutedEventArgs e)
{
ToggleClick?.Invoke(FoodId);
}
The dependency property that hook to the toggle button also enable OnNotifyPropertyChanged
in this code notice that I expose the ToggleButton_Click to let the Page that contain the gridview can handle the click. And here's how I handle it
private void FoodCard_ToggleClick(int foodId)
{
foreach(FoodDTO dto in Foods)
{
dto.IsSelected = false;
}
foreach (FoodDTO dto in Foods)
{
System.Diagnostics.Debug.WriteLine(dto.IsSelected);
System.Diagnostics.Debug.WriteLine("-------------");
}
}
I watch the console they are all output IsSelected is False, but the Toggle Button on the ui element doesn't de-toggle. Here is the FoodDTO
public class FoodDTO
{
public int FoodId { get; set; }
public string FoodName { get; set; }
public string FoodEnglishName { get; set; }
public int MainIcon { get; set; } = 5;
public int? SecondaryIcon { get; set; }
public decimal Percentage { get; set; }
public bool IsSelected { get; set; }
}
The reason the UI does not react to the change in IsSelected property is that the FoodDto is a POCO, and does not implement INotifyPropetyChanged. If you make sure to raise PropertyChanged when IsSelected changes, it will be reflected in the x:Bind in the DataTemplate and will also then flow into your UserControl.
In my Xamarin.Forms app, I have MaterialFrame custom control.
iOS renderer works great and looks like:
public class MaterialFrameRenderer : FrameRenderer
{
private const int ShadowColor = 0x939393;
public override void Draw(
CGRect rect)
{
base.Draw(rect);
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = Layer.CornerRadius;
Layer.ShadowColor = ColorHelper.FromHex(ShadowColor).CGColor;
Layer.ShadowOffset = new CGSize(1, 1);
Layer.ShadowOpacity = 0.30f;
Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
Layer.MasksToBounds = false;
}
}
On Android platform I want to use implementation based on my other cross-platform control. My .net standard(shared project) implementation:
public class MaterialFrame : Frame
{
public MaterialFrame()
{
if (Device.RuntimePlatform == Device.Android)
{
Content = new MyOtherCustomControl
{
BackgroundColor = Color.Red
};
}
}
}
Unfortunately this implementation doesn't work on Android. Do you have any suggestion?
I create the MyOtherCustomControl.
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="MyOtherCustomControl"
VerticalOptions="CenterAndExpand" />
<Button />
</StackLayout>
And use it in MaterialFrame custom control.
public class MaterialFrame : Frame
{
public MaterialFrame()
{
if (Device.RuntimePlatform == Device.Android)
{
Content = new MyOtherCustomControl
{
BackgroundColor = Color.Red
};
}
}
}
Usage of MaterialFrame:
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<pages:MaterialFrame />
</StackLayout>
</ContentPage.Content>
Screenshot:
I have two pages MainPage and SecondPage1 .in App.xaml.cs I Navigate to Secondpage1 using this code:
App.xaml.cs :
//MainPage = new Fmkt44Application.MainPage();/*First Approach*/
MainPage = new NavigationPage(new MainPage());/*Second approach*/
MainPage.xaml.cs:
// App.Current.MainPage = new NavigationPage(new SecondPage1());/*First Approach*/
await Navigation.PushAsync(new SecondPage1());/*Second approach*/
Problem is if I use both approaches I can navigate to secondpage1 but if I use second approach I cant write on searchbar or any entries. What is the reason and how can I Fix it?
Here is MainPage.xaml.cs
namespace Fmkt44Application
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
public async System.Threading.Tasks.Task LoginControlAsync(Object sender, EventArgs args)
{
User.UserName = entry_user.Text;
User.Password = entry_passw.Text;
if (User.CheckUserInformation() == false)
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresini giriniz", "OK");
}
else
{
String val = entry_user.Text + "$" + entry_passw.Text;
CallIasWebService.Login();
String rval = CallIasWebService.CallIASService("PROFILECONTROL", val);
CallIasWebService.Logout();
User.Profile = rval.ToString();
if (rval != "0" )
{
if (User.Profile != "" && User.Profile != null)
{
// App.Current.MainPage = new NavigationPage(new SecondPage1());if I Call Like this I can write on Secondpage1 (First approach)
await Navigation.PushAsync(new SecondPage1());/*I cannot reach SecondPage1 controls/* (second approach)*/
}
else
{
DisplayAlert("Login", "Kayıt yapma yetkiniz yoktur.", "OK");
}
}
else
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresi hatalıdır.", "OK");
}
}
}
public async System.Threading.Tasks.Task scanncontrolAsync(Object sender, EventArgs E)
{
// await Navigation.PushAsync(new SecondPage1());
App.Current.MainPage = new SecondPage1();
}
}
}
App.cs is
public App ()
{
InitializeComponent();
//MainPage = new Fmkt44Application.MainPage();(First apploach)
MainPage = new NavigationPage(new MainPage());/*second approach*/
}
Secondpage1.xaml is
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Fmkt44Application.SecondPage1">
<ContentPage.Content>
<StackLayout>
<SearchBar Placeholder="Ara..." TextChanged="TextChange" x:Name="searchbar" />
<ListView x:Name="Materials" ItemTapped="MakineSec" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="{Binding Material}"/>
<Label Text="{Binding Stext}"/>
</StackLayout>
<Entry Text="{Binding SerialNumber}" />
</StackLayout>
<ViewCell.ContextActions>
<MenuItem Text="Seç" Clicked="MakineSec" CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Problem comes from Android Emulator. I tried a real tablet problem solved.
first of all sorry for my english.
I am working on a iOS and Android project using Xamarin.Form
I would like to have a 'xaml user control' reusable in different way, and I need to make it clickable with ICommand
This is the StackLayoutButton component:
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Installa.Controls.StackLayoutButton">
<Image x:Name="Icon" Source="{Binding Icon}" />
<Label x:Name="Text" Text="{Binding Title}" HorizontalOptions="Center" LineBreakMode="NoWrap" Font="Small" TextColor="Red" />
</StackLayout>
This is the CalendarioPage xaml page where the component is used
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Installa.Controls;assembly=Installa"
x:Class="Installa.CalendarioPage">
<StackLayout>
<Label Text="{Binding ViewName}" Font="42" IsVisible="{Binding IsWindowsPhone}" />
<ActivityIndicator IsRunning="{Binding IsLoading}" IsVisible="{Binding IsLoading}" Color="Red" />
<controls:StackLayoutButton BindingContext="{Binding Blog}" TextColor="Blue" /> <!-- Command="{Binding SubmitCommand}" -->
<controls:StackLayoutButton BindingContext="{Binding Facebook}" TextColor="Red" /> <!-- Command="{Binding SubmitCommand}" -->
</StackLayout>
</ContentPage>
This is the CalendarioPage c# page:
public partial class CalendarioPage : ContentPage
{
private CalendarioViewModel vm;
public CalendarioPage()
{
InitializeComponent();
vm = new CalendarioViewModel();
this.BindingContext = vm;
}
}
This is the viewmodel class:
namespace Installa
{
public class CalendarioViewModel: BaseViewModel
{
public CalendarioViewModel()
{
blog = new Activity();
blog.Link = "www.google.it";
blog.Title = "Titolo del blog";
blog.Icon = "logomenu.png";
facebook = new Activity();
facebook.Title = "Tito Fbook";
facebook.Link = "www.facebook.it";
facebook.Icon = "icon.png";
ViewName = "nome della view";
IsLoading = false;
}
Activity blog = null;
public Activity Blog
{
get {return blog;}
}
Activity facebook = null;
public Activity Facebook
{
get { return facebook; }
}
string viewName = string.Empty;
public string ViewName
{
get { return viewName; }
set { SetProperty(ref viewName, value); }
}
public bool IsWindowsPhone
{
get
{
return Device.OS == TargetPlatform.WinPhone;
}
}
bool isLoading = false;
public bool IsLoading
{
get { return isLoading; }
set { SetProperty(ref isLoading, value); }
}
}
}
With Activity a simple class with:
public string Title { get; set; }
public string Link { get; set; }
public String Icon { get; set; }
Till now, all is working right, but now I need to implement the ICommand interface.
In StackLayoutButton c# code I try to add:
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, "TapCommand");
Icon.GestureRecognizers.Add(tapGestureRecognizer)
Text.GestureRecognizers.Add(tapGestureRecognizer)
Furthermore I try to add into CalendarioViewModel INotifyPropertyChanged and the 'OnTapped' method.
Into Activity.cs i add 'ICommand tapCommand' and the related get...but is not working.
I try even other..but I am not able to enable the tap on the StackLayoutButton components.
In wich way I should do ?
I'd like to be able to have a 'programmable' command...for example I would like browse to 'the link property' of Activity or be able to open a new view.
Thanks for help!
Update:
I was able to add TapGestureRecognizer into the xaml user control (StackLayoutButton.xaml.cs),
but I'd like to implement it in MVVM way,
using Xamarin.Forms;
namespace Installa.Controls
{
public partial class StackLayoutButton : StackLayout
{
public StackLayoutButton()
{
InitializeComponent();
TapGestureRecognizer tapGestureRecognizer = new TapGestureRecognizer
{
Command = new Command(OnMyComponentTapped),
CommandParameter = "ciao"
};
this.Icon.GestureRecognizers.Add(tapGestureRecognizer);
this.Text.GestureRecognizers.Add(tapGestureRecognizer);
}
async void OnMyComponentTapped(object parameter)
{
// do action
}
public Color TextColor
{
get { return this.Text.TextColor; }
set { this.Text.TextColor = value; }
}
public Label TextControl
{
get { return this.Text; }
set { this.Text = value; }
}
}
}
can anyone suggest me the way ?
Thanks
This is how I add gesture recognizer on my xaml view:
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SelectEquipmentCommand}"/>
</Label.GestureRecognizers>
And this is the ICommand property in my ViewModel:
public ICommand SelectEquipmentCommand
{
get
{
return fSelectEquipmentCommand ?? (fSelectEquipmentCommand = new Command(async () => await SelectEquipmentTask()));
}
}
private async Task SelectEquipmentTask()
{
}
I have a class named MizahPanoramaItems, a List named PanoramaKarikaturItems and a ViewModel named MizahViewModel. My problem is my listbox' datatemplate's events not working.
<Grid x:Name="LayoutRoot" Background="White">
<phone:Panorama SelectionChanged="panaromaMain_SelectionChanged"
x:Name="panaromaMain" Title="mizah"
Style="{StaticResource PanoramaStyle}"
Background="#FFECF0F1" Foreground="#FF040202">
<phone:Panorama.TitleTemplate>
<DataTemplate>
<!--<TextBlock Text="{Binding}" FontSize="100" Margin="0,20,0,0"></TextBlock>-->
</DataTemplate>
</phone:Panorama.TitleTemplate>
<phone:PanoramaItem x:Name="panoramaKarikatur" Header="karikatür" Orientation="Horizontal" Foreground="#A6CC33">
<ListBox Margin="0,0,0,10" ItemsSource="{Binding PanoramaKarikaturItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<MetroEventToCommand:EventToCommandManager.Collection>
<MetroEventToCommand:EventToCommand Command="{Binding PanoramaTypeSelection}" Event="Tap"/>
</MetroEventToCommand:EventToCommandManager.Collection>
<c4f:Tile Width="410" Height="200" Margin="0,12,0,0" Background="{Binding ElementName=panoramaKarikatur,Path=Foreground}" Label="{Binding Name}" Foreground="White">
<Grid>
<c4f:TileNotification Background="White" Content="{Binding Count}" Foreground="{Binding ElementName=panoramaKarikatur,Path=Foreground}"/>
<Image Source="{Binding ImagePath,Converter={StaticResource UriToImage}}" Stretch="None" Width="140" Height="150" VerticalAlignment="Center" HorizontalAlignment="Center" />
</Grid>
</c4f:Tile>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</phone:PanoramaItem>.....
Here is my list in ViewModel;
private List<MizahPanoramaItems> panoramaKarikaturItems;
public List<MizahPanoramaItems> PanoramaKarikaturItems
{
get { return panoramaKarikaturItems; }
set { SetProperty<List<MizahPanoramaItems>>(ref panoramaKarikaturItems, value, "PanoramaKarikaturItems"); }
}
Here is my MizahPanoramaItems Class
public class MizahPanoramaItems:NotifyPropertyChanged
{
public MizahPanoramaItems()
{
PanoramaTypeSelection = new DelegateCommand(PanoramatypeSelectionAction);
}
public enum Types
{
Caps,
Karikatur,
DiziFilm
}
private int _count;
public int Count
{
get { return _count; }
set { SetProperty<int>(ref _count, value, "Count"); }
}
private Types _type;
public Types Type
{
get { return _type; }
set { SetProperty<Types>(ref _type, value, "Type"); }
}
private string _path;
public string Path
{
get { return _path; }
set { SetProperty<string>(ref _path, value, "Path"); }
}
private string _pathName;
public string PathName
{
get { return _pathName; }
set { SetProperty<string>(ref _pathName, value, "PathName"); }
}
private string _imagePath;
public string ImagePath
{
get { return _imagePath; }
set { SetProperty<string>(ref _imagePath, value, "ImagePath"); }
}
private string _name;
public string Name
{
get { return _name; }
set { SetProperty<string>(ref _name, value, "Name"); }
}
public ICommand PanoramaTypeSelection { get; set; }
public void PanoramatypeSelectionAction()
{
}
}
and my command implementation;
public ICommand PanoramaTypeSelection { get; set; }
public void PanoramatypeSelectionAction()
{
//it is not working
}
public MizahPanoramaItems()
{
PanoramaTypeSelection = new DelegateCommand(PanoramatypeSelectionAction);
}