How do you bind to a Grid in a ItemsPanel? - binding

I am building a custom control based on ItemsControl. I am trying to bind to the grid contained in the ItemsPanelTemplate. I cannot seem to get the binding correct. Any help is appreciated!
<local:MyItemsControl Height="500" Width="500" Margin="50" gRow="1">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Background="Red" >
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</local:MyItemsControl>
Here is my class:
public class MyItemsControl : ItemsControl
{
public MyItemsControl()
{
this.DefaultStyleKey = typeof(ItemsControl);
}
public int gRow { get; set; }
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
if (element is FrameworkElement)
{
(element as ContentPresenter).SetBinding(Grid.RowProperty, new Binding {Source = item, Path = new PropertyPath("gRow")});
}
}
}

You sure can!
Using this XAML:
<local:MyItemsControl>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.RowSpan="{Binding RowSpan}"
Grid.ColumnSpan="{Binding ColumnSpan}"
Grid.Row="{Binding Row}"
Grid.Column="{Binding Column}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<local:MyItem Text="One" Row="0" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Text="Two" Row="1" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Text="Three" Row="0" RowSpan="1" Column="1" ColumnSpan="1" />
<local:MyItem Text="Four" Row="1" RowSpan="1" Column="1" ColumnSpan="1" />
</local:MyItemsControl>
Use this code:
public class MyItem
{
public string Text { get; set; }
public int Row { get; set; }
public int RowSpan { get; set; }
public int Column { get; set; }
public int ColumnSpan { get; set; }
public override string ToString()
{
return Text;
}
}
public class MyItemsControl : ItemsControl
{
protected override DependencyObject GetContainerForItemOverride()
{
var container = base.GetContainerForItemOverride() as FrameworkElement;
if (container == null) return container;
var content = ItemTemplate.LoadContent() as FrameworkElement;
if (content == null) return container;
// sync the container grid dependency properties with the content
var binding = content.GetBindingExpression(Grid.RowProperty);
if (binding != null)
container.SetBinding(Grid.RowProperty, content.GetBindingExpression(Grid.RowProperty).ParentBinding);
binding = content.GetBindingExpression(Grid.RowSpanProperty);
if (binding != null)
container.SetBinding(Grid.RowSpanProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnProperty);
if (binding != null)
container.SetBinding(Grid.ColumnProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnSpanProperty);
if (binding != null)
container.SetBinding(Grid.ColumnSpanProperty, binding.ParentBinding);
return container;
}
}
Best of luck!

Related

Return listview value from ItemTapped to filter firebase call - Selected item returns as null

I have tried adding the data to Listview using the public class 'Videotag' and a list 'initialList'. I'm trying to compare the listview selected item value to tags data from the RealtimeFirebase. The data from the firebase calls fine, but selected item value from listview returns null. Anyone know what i'm doing wrong?
public partial class videosection : ContentPage
{
List<videos> allVideos = new List<videos>();
List<Videotag> item = new List<Videotag>();
//List<string> initialList = new List<string>();
public videosection()
{
InitializeComponent();
//DependencyService.Get<IRotate>().ForcePortrait();
//initialList.Add("Shoulders");
//initialList.Add("Core");
//initialList.Add("Arms");
//initialList.Add("Hands");
//initialList.Add("Legs");
//initialList.Add("Balance");
//VideoLV.ItemsSource = initialList;
item.Add(new Videotag() { tags = "Shoulders" });
item.Add(new Videotag() { tags = "Core" });
item.Add(new Videotag() { tags = "Arms" });
item.Add(new Videotag() { tags = "Hands" });
item.Add(new Videotag() { tags = "Legs" });
item.Add(new Videotag() { tags = "Balance" });
VideoLV.ItemsSource = item;
//VideoLV.selectedi = item[0];
getvideo();
}
public class Videotag
{
public string tags { get; set; }
}
async private void getvideo()
{
allVideos = await DbFirebase.Getvideos();
//Adds videos to ItemsSource depending on the currently selected tag
//videosListView.ItemsSource = allVideos.Where(v => v.tag.Trim().ToLower() == (VideoLV.SelectedItem).ToString().Trim().ToLower()).ToList();
}
//private void SfChipGroup_SelectionChanged(object sender, Syncfusion.Buttons.XForms.SfChip.SelectionChangedEventArgs e)
//{
// videosListView.ItemsSource = allVideos.Where(v => v.tag.Trim().ToLower() == ((SfChip)chips.SelectedItem).Text.Trim().ToLower()).ToList();
//}
private async void Watch_Button_Clicked(object sender, EventArgs e)
{
string videoId = (string)((ImageButton)sender).BindingContext;
var video = allVideos.FirstOrDefault(v => v.id == videoId);
await Navigation.PushModalAsync(new SingleVideo(video), false);
}
private void VideoLV_ItemTapped(object sender, Syncfusion.ListView.XForms.ItemTappedEventArgs e)
{
//var indexes = e.ToString();
//String selectedFromList = VideoLV.getItemAtPosition(position);
//int myindex = VideoLV.Index(tags);
//vaVideoLV.selectedItem
//var selected = (videotag)e.SelectedItem;
videosListView.ItemsSource = allVideos.Where(v => v.tag.Trim().ToLower() == ((SfListView)VideoLV.SelectedItem).ToString().Trim().ToLower()).ToList();
}
<syncfusion:SfListView x:Name="VideoLV"
Padding="0"
AutoFitMode="Height"
Margin="10,0,10,0"
ItemTapped="VideoLV_ItemTapped"
BackgroundColor="Transparent"
SelectionMode="Single"
VerticalOptions="StartAndExpand"
IsScrollBarVisible="False"
SelectionBackgroundColor="Transparent"
Orientation="Horizontal"
HeightRequest="55">
<syncfusion:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame CornerRadius="10" Margin="5,0,5,0" BackgroundColor="LightBlue" HasShadow="False" >
<Grid HorizontalOptions="StartAndExpand" Margin="0" Padding="0" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="{Binding tags}" Margin="0,-5,0,0" Grid.Row="0" VerticalOptions="StartAndExpand" TextColor="Black" FontSize="Small" />
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</syncfusion:SfListView.ItemTemplate>
<syncfusion:SfListView.SelectedItemTemplate>
<DataTemplate>
<ViewCell>
<Frame CornerRadius="10" Margin="5,0,5,0" BackgroundColor="LightBlue" HasShadow="False" BorderColor="Red">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Text="{Binding tags}" Margin="0,-5,0,0" VerticalOptions="CenterAndExpand" Grid.Row="0" TextColor="Red" FontSize="Small" />
</Grid>
</Frame>
</ViewCell>
</DataTemplate>
</syncfusion:SfListView.SelectedItemTemplate>
</syncfusion:SfListView>
you are trying to cast SelectedItem to SfListView, which is wrong
(SfListView)VideoLV.SelectedItem
the SelectedItem should be a Videotag
(Videotag)VideoLV.SelectedItem

Xamarin Forms Listview will not display on my iPone. However, it does on the simulator

I have tried everything I could think of and everything I found on the web and have not had any luck, still a blank page.
here is my xaml file;
<ListView x:Name="AutoView" ItemsSource="{Binding AutoData}" SelectedItem="{Binding SelectedItem}" SeparatorVisibility="None" Grid.Row="1" Grid.ColumnSpan="6" BackgroundColor="Purple">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="27"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="65"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="55"/>
<ColumnDefinition Width="65"/>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="36"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" FontSize="Medium" TextColor="White" Text="{Binding Year}" HorizontalTextAlignment="Center"/>
<Label Grid.Column="2" Grid.Row="0" FontSize="Medium" TextColor="White" Text="{Binding Name}" HorizontalTextAlignment="Start" Grid.ColumnSpan="2"/>
<Switch x:Name="{Binding Id}" IsToggled="{Binding IsChecked, Mode=TwoWay}" Toggled="Handle_Toggled" Grid.Column="6" Grid.Row="0" Grid.ColumnSpan="2"/>
</Grid>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
My code in my view model looks like this, I have changed it multiple times but this is where it is at now.
public ObservableCollection<AutoWithSwitch> MyList = new ObservableCollection<AutoWithSwitch>();
public ObservableCollection<AutoWithSwitch> AutoData = new ObservableCollection<AutoWithSwitch>(); //{ get { return MyList; } }
private IPopupNavigation _popup { get; set; }
private PopupPage _modalPage;
public event PropertyChangedEventHandler PropertyChanged;
public UpdateCarsViewModel()
{
//Analytics.TrackEvent("Top of Constructor in UpdateCarsViewModel");
GetDisplayData();
Sort.SortOrder(MyList, i => i.Year, false);
_popup = PopupNavigation.Instance;
_modalPage = new PopupPage();
}
public void GetDisplayData()
{
MileageItemRepository repository = new MileageItemRepository();
var response = repository.GetAuto2();
//MyList.Clear();
foreach (var item in response)
{
Analytics.TrackEvent("Car Data GetDisplayData: carId " + item.Id + " Name = " + item.CarDesc + " Year = " + item.CarYear);
AutoData.Add(new AutoWithSwitch
{
Id = item.Id,
Year = item.CarYear,
Name = item.CarDesc,
IsChecked = item.IsDefault
});
Analytics.TrackEvent("In GetDisplayData in UpdateCarsViewModel CarYear = " + item.CarYear);
}
//AutoData = MyList;
}
As you can see I have logging in there and I can see the car information being retrieved from the DB table, it just will not display.
Per your code snippets, ListView controls is binding to AutoData of type ObservableCollection and the data in side of list view will be binding to the properties of the class AutoWithSwitch to the four properties:
Id,Year,Name and IsChecked.
So you should claim and use the AutoData with set and get property like below:
public class UpdateCarsViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<AutoWithSwitch> mylist;
public ObservableCollection<AutoWithSwitch> AutoData
{
get { return mylist; }
set { mylist = value; }
}
public UpdateCarsViewModel()
{
GetDisplayData();
}
public void GetDisplayData()
{
//get data logic
AutoData = new ObservableCollection<AutoWithSwitch>()
{
new AutoWithSwitch()
{
Id = "1",
Year = "2022",
Name = "Steve_Jobs",
IsChecked = false
}
};
}
}
}
Note:Make sure you can successfully retrieve data from below,
MileageItemRepository repository = new MileageItemRepository();
var response = repository.GetAuto2();
This was helpful and aswered my question. Hope this is what you meant by answering that it was helpful.

Xamarin.ios - resx reference in xaml file not working

I've a AppResources.resx file where I store all strings that I use across my app. My Xamarin project contains two solutions one for Android and another for iOS. The Android app is working perfectly. But the iOS app is throwing Xaml errors that say something like "Cannot found static member AppResources".
Here's my xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:HalliganTL;assembly=HalliganTL"
x:Class="HalliganTL.View.LoginPage">
<Grid Style="{StaticResource backgroundColor}">
<Grid.RowDefinitions>
<RowDefinition Height="4*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Entry x:Name="entryEmail"
Placeholder="{x:Static local:AppResources.login_page_email_placeholder}" Text="{Binding Username}" Grid.Row="1" Grid.Column="1" />
<Entry x:Name="entryPassword"
Placeholder="{x:Static local:AppResources.login_page_password_placeholder}"
Text="{Binding Password}" IsPassword="true" Grid.Row="2" Grid.Column="1"/>
<ActivityIndicator x:Name="activityIndicator" IsRunning="False" Grid.Row="3" Grid.Column="1" />
<Button Text="{x:Static local:AppResources.login_page_login_button_text}"
Style="{StaticResource redButton}" Clicked="OnLoginButtonClicked" Grid.Row="4" Grid.Column="1"/>
<Button Text="{x:Static local:AppResources.login_page_forgot_password_button_text}"
Style="{StaticResource blueButton}" Clicked="OnForgotPasswordClicked" Grid.Row="5" Grid.Column="1"/>
</Grid>
</ContentPage>
Any tip about what can be causing this error?
UPDATE
I removed all AppResources.resx references in the XAML file, and yet It throws an error telling me that the "OnLoginButtonClicked" method doesn't exist in the .cs code. But It clearly does!
Here's my .cs code:
using Newtonsoft.Json;
using HalliganTL.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using XLabs.Ioc;
namespace HalliganTL.View
{
public partial class LoginPage : ContentPage
{
public LoginPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
Title = AppResources.login_page_title;
BindingContext = new MainViewModel();
}
async void OnForgotPasswordClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new ForgotPasswordPage());
}
async void OnLoginButtonClicked(object sender, EventArgs e)
{
//Validates email
if (!HalliganUtils.IsValidEmail(entryEmail.Text))
{
await DisplayAlert(AppResources.error_title,
AppResources.login_page_email_validation_error,
AppResources.accept_button_text);
return;
}
//Validates password
if (!HalliganUtils.IsValidPassword(entryPassword.Text))
{
await DisplayAlert(AppResources.error_title,
AppResources.login_page_password_validation_error,
AppResources.accept_button_text);
return;
}
HalliganCredential credentials = new HalliganCredential
{
Email = entryEmail.Text,
Password = entryPassword.Text
};
await App.RestClient.GetUserAuthAsync(credentials)
.OnSuccess((result) =>
{
Navigation.InsertPageBefore(new MainPage(), this);
Navigation.PopAsync();
})
.OnRequestStarted(() =>
{
activityIndicator.IsRunning = true;
entryEmail.IsEnabled = false;
entryPassword.IsEnabled = false;
})
.OnRequestCompleted(() =>
{
activityIndicator.IsRunning = false;
entryEmail.IsEnabled = true;
entryPassword.IsEnabled = true;
})
.OnHttpError((exception) =>
{
DisplayAlert(AppResources.error_title,
AppResources.login_page_login_failed_message,
AppResources.accept_button_text);
})
.OnUnknownError((exception) =>
{
DisplayAlert(AppResources.error_title,
AppResources.unknown_error,
AppResources.accept_button_text);
})
.Start();
}
}
}
UPDATE
I tried changing the method signatures but didn't work. What I tried:
public async void OnForgotPasswordClicked(object sender, EventArgs e)
and
public void OnForgotPasswordClicked(object sender, EventArgs e)

How do I bind a Dataset to a Datagrid with an ObjectDataProvider?

i've got another binding problem.
This time I wanted to rebuild the Master-Detail grid shown here:
http://www.codeproject.com/Articles/30905/WPF-DataGrid-Practical-Examples#masterdetail
But I got this Error: The name "AirplaneDataProvider" does not exist in the namespace "clr-namespace:WpfApplicationDataSetTest"
Here's my code
XAML:
<Window x:Class="WpfApplicationDataSetTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplicationDataSetTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ObjectDataProvider x:Key="AirplaneDataProvider" ObjectType="{x:Type local:AirplaneDataProvider}"/>
<ObjectDataProvider x:Key="Airplanes" ObjectInstance="{StaticResource AirplaneDataProvider}" MethodName="GetAirplanes" />
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<DataGrid Name="DGMaster" Grid.Row="0" ItemsSource="{Binding Source={StaticResource Airplanes}}" SelectedValuePath="AirplaneID">
</DataGrid>
</Grid>
c#:
namespace WpfApplicationDataSetTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public class AirplaneDataProvider
{
private AirplaneTestDataSetTableAdapters.AirplaneTableAdapter AirTA;
private AirplaneTestDataSet AirTDS;
public AirplaneDataProvider()
{
AirTDS = new AirplaneTestDataSet();
AirTA = new AirplaneTestDataSetTableAdapters.AirplaneTableAdapter();
AirTA.Fill(AirTDS.Airplane);
}
public DataView GetAirplanes()
{
return AirTDS.Airplane.DefaultView;
}
}
}
}
So what am I doing wrong?
Put the AirplaneDataProvider class into separated file.
Now you have it inside MainWindow class. hope that is the problem.

Creating a LoginStatusControl in Silverlight

I'm trying to create a login status control in silverlight where I will use multiple ControlTemplates to define conditional content.
So far I have created a LoginStatusControl
public class LoginStatusControl : ContentControl
{
// these are actually Depedency Properties
public ControlTemplate LoggedInTemplate { get; set; }
public ControlTemplate AnonymousTemplate { get; set; }
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var user = this.DataContext as User;
if (user == null && this.AnonymousTemplate != null)
{
this.Template = this.AnonymousTemplate;
}
else if (this.LoggedInTemplate != null)
{
this.Template = this.LoggedInTemplate;
}
}
}
Then I've defined the templates in a Style.
<Style x:Key="UserStatusStyle" TargetType="local:LoginStatusControl">
<Setter Property="LoggedInTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="User " />
<TextBlock Text="{Binding FirstName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding LastName}" />
<TextBlock Text=" is logged in" />
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="AnonymousTemplate">
<Setter.Value>
<ControlTemplate>
<TextBlock Text="Please create your profile" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I'm having difficulty getting the conditional templates connected to override the ControlTemplate.
While searching I found this question and tried to use template binding but I couldn't get that to work.
Is there anyway to get this conditional templates to display if the user is logged in or not? Is there another way of solving this problem that I'm missing? I'm hoping to come up with a solution that can update the template dynamically when the DataContext of the control changes.
Well, I ended up going with a ContentContent's Content property and providing conditional DataTemplates.
Here is the Control:
public class LoginStatusControl : ContentControl
{
public DataTemplate LoggedInTemplate
{
get { return (DataTemplate)GetValue(LoggedInTemplateProperty); }
set { SetValue(LoggedInTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for LoggedInTemplate. This enables animation, styling, binding, etc...
public static readonly DependencyProperty LoggedInTemplateProperty =
DependencyProperty.Register("LoggedInTemplate", typeof(DataTemplate), typeof(LoginStatusControl), new PropertyMetadata(null));
public DataTemplate AnonymousTemplate
{
get { return (DataTemplate)GetValue(AnonymousTemplateProperty); }
set { SetValue(AnonymousTemplateProperty, value); }
}
// Using a DependencyProperty as the backing store for AnonymousTemplate. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AnonymousTemplateProperty =
DependencyProperty.Register("AnonymousTemplate", typeof(DataTemplate), typeof(LoginStatusControl), new PropertyMetadata(null));
public LoginStatusControl()
{
DefaultStyleKey = typeof(LoginStatusControl);
}
public override void OnApplyTemplate()
{
UpdateTemplate();
base.OnApplyTemplate();
}
private void UpdateTemplate()
{
var content = (ContentControl)base.GetTemplateChild("LoginControl");
if (content == null)
return;
var user= this.DataContext as User;
if (user == null && this.AnonymousTemplate != null)
{
content.Content = this.DataContext;
content.ContentTemplate = this.AnonymousTemplate;
}
else if (this.LoggedInTemplate != null)
{
content.Content = this.DataContext;
content.ContentTemplate = this.LoggedInTemplate;
}
}
}
And here is the Default Style.
<Style x:Key="LoginStatusStyle" TargetType="controls:LoginStatusControl">
<Setter Property="LoggedInTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="User: "/>
<TextBlock Text="{Binding FirstName}" FontWeight="Bold" />
<TextBlock Text=" " />
<TextBlock Text="{Binding LastName}" FontWeight="Bold" />
<TextBlock Text=" is logged in" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="AnonymousTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="Please create your profile" />
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ContentControl x:Name="LoginControl" Margin="10,0" VerticalAlignment="Center" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Resources