Can I populate a Label within my CollectionView with a value outside the ItemsSource List that populates the view? - binding

I have a Label within my CollectionView that I need to populate with a value outside the ItemsSource List that populates the view.
The following code is an example of what I am trying to accomplish but it seems that the CollectionView is limiting the binding context to just the Items list. I have tried naming the label and setting it in my c# code but I cant seem to access the label in c#. I suppose I could build the whole page in c# rather than using the .xaml but unlike this example my actual code uses multiple templates and a template selector. If I could figure this out without rewriting hours of code I would prefer it.
ItemsPage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="TabTest.Views.ItemsPage"
Title="{Binding Title}"
x:Name="BrowseItemsPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="AddItem_Clicked" />
</ContentPage.ToolbarItems>
<StackLayout Padding="10">
<Label Text="{Binding TestVal}" FontSize="16" HeightRequest="20" />
<!-- ^^^^ This label displays just as expected -->
<RefreshView IsRefreshing="{Binding IsBusy, Mode=TwoWay}" Command="{Binding LoadItemsCommand}">
<CollectionView x:Name="ItemsCollectionView"
ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10">
<Label x:Name="TestV" Text="{Binding Path=BindingContext.TestVal}" />
<!-- ^^^^ I want this Label to display the TestVal string in the ViewModel -->
<Label Text="{Binding Text}"
d:Text="{Binding .}"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemTextStyle}"
FontSize="16" />
<Label Text="{Binding Description}"
d:Text="Item descripton"
LineBreakMode="NoWrap"
Style="{DynamicResource ListItemDetailTextStyle}"
FontSize="13" />
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" Tapped="OnItemSelected"></TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
</StackLayout>
</ContentPage>
ItemsViewModel.cs
namespace TabTest.ViewModels
{
public class ItemsViewModel : BaseViewModel
{
public ObservableCollection<Item> Items { get; set; }
public Command LoadItemsCommand { get; set; }
private string testVal;
public string TestVal // I want the value of this variable in that Label
{
get
{
return testVal;
}
set
{
testVal = value;
}
}
public ItemsViewModel()
{
Title = "Browse";
TestVal = "Value123";
Items = new ObservableCollection<Item>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
MessagingCenter.Subscribe<NewItemPage, Item>(this, "AddItem", async (obj, item) =>
{
var newItem = item as Item;
Items.Add(newItem);
await DataStore.AddItemAsync(newItem);
});
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStore.GetItemsAsync(true);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}

I ended up using a dynamic resource in Xaml and used code behind to modify the resource when it needed to change.
Xaml:
<Label x:Name="TestV" Text="{DynamicResource TestValue}" />
Code Behind:
Application.Current.Resources["TestValue"] = NewValue;
App.xaml:
<x:String x:Key="TestValue">Value123</x:String>

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.

Binding with BasePage in Xamarin Forms

I am implementing a Xamarin app with FreshMVVM framework and I want to use a BasePage to share some code among Pages.
The problem is that when I need to bind some Properties in the MainPage.xaml I have to specify the Source in this way to make it working: Text="{Binding Title, Source={x:Reference mainPage}}". Otherwise without Source Binding doesn't work.
Ok, I get it but is this the right way? Is there another way to achieve the same result? What about when I have plenty of bindings in a page? For instance, is it possible "setting" the Source at un upper level, because in my opinion setting the same Source for each Binding is very annoying.
BasePage.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="TestXamarin.BasePage"
x:Name="basePage">
<ContentView>
<StackLayout Orientation="Vertical">
<Label Text="HEADER" FontSize="Large"/>
<Label Text="{Binding Text, Source={x:Reference basePage}}" FontSize="Large"/>
<ContentPresenter BindingContext="{Binding Parent.BindingContext}"
Content="{Binding PageContent, Source={x:Reference basePage}}" />
</StackLayout>
</ContentView>
</ContentPage>
BasePage.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TestXamarin
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class BasePage : ContentPage
{
public static readonly BindableProperty TextProperty = BindableProperty.Create(
nameof(Text),
typeof(string),
typeof(BasePage));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly BindableProperty PageContentProperty = BindableProperty.Create(
nameof(PageContent),
typeof(object),
typeof(BasePage));
public object PageContent
{
get { return GetValue(PageContentProperty); }
set { SetValue(PageContentProperty, value); }
}
public BasePage()
{
InitializeComponent();
}
}
}
MainPage.xaml
<local:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TestXamarin"
x:Class="TestXamarin.MainPage"
Text="FROM MAIN PAGE"
x:Name="mainPage">
<local:BasePage.PageContent>
<StackLayout>
<Label Text="Body" FontSize="Large"/>
<Label Text="{Binding Title, Source={x:Reference mainPage}}" FontSize="Large"/>
</StackLayout>
</local:BasePage.PageContent>
</local:BasePage>
MainPage.xaml.cs
public partial class MainPage : BasePage
{
public MainPage()
{
Title = "MAIN PAGE";
InitializeComponent();
}
}
Another way to achieve what you are trying to do would be with control templates.
Here I have defined a template in App.xaml
<ControlTemplate x:Key="ActivityIndicatorTemplate">
<Grid>
<ContentPresenter />
<StackLayout Style="{StaticResource BlockingPanel}"
IsVisible="{TemplateBinding BindingContext.IsBusy}">
<ActivityIndicator Style="{StaticResource ActivityIndicatorStyle}"
IsVisible="{TemplateBinding BindingContext.IsBusy}"
IsRunning="{TemplateBinding BindingContext.IsBusy}" />
</StackLayout>
</Grid>
</ControlTemplate>
Note the content presenter and the TemplateBinding.
I use it on a page like this.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.MyTestPage"
ControlTemplate="{StaticResource ActivityIndicatorTemplate}"
Title="{Binding Title}">
<Grid>
...
</Grid>
</ContentPage>
The page content replaces the content presenter in the template. Looks simpler than a base page.

Listbox binding get selected item value

I'm new in Wpf and i face issue to get selected item in listbox
I created a simple xaml with a listbox and a textbox.
I use binding to populate my listbox including trigger (checked or not) that i want ot use later.
Xaml code:
<ListBox x:Name="LstB_Checklist" HorizontalAlignment="Left" Height="190" Margin="39,45,0,0" VerticalAlignment="Top" Width="275" Background="#FF363636" BorderBrush="{x:Null}" FontSize="18" Foreground="White" BorderThickness="2" SelectionChanged="LstB_Checklist_SelectionChanged" SelectedItem="{Binding SelectedProperty,Mode=TwoWay}" >
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Background" Value="#FFFFDC00" />
<Setter Property="Foreground" Value="Black" />
</Trigger>
</Style.Triggers>
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightGray"/>
</Style.Resources>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image>
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Checked}" Value="false">
</DataTrigger>
<DataTrigger Binding="{Binding Checked}" Value="true">
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<TextBlock Text="{Binding Path=Title, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox x:Name="txtb_Selection" HorizontalAlignment="Left" Height="23" Margin="60,264,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120"/>
in the code behind
public MainWindow()
{
InitializeComponent();
List<LstB_Item> items = new List<LstB_Item>();
items.Add(new LstB_Item() { Title = "Items 1", Checked = false });
items.Add(new LstB_Item() { Title = "Items 2", Checked = false });
items.Add(new LstB_Item() { Title = "Items 3", Checked = false });
LstB_Checklist.ItemsSource = items;
}
public class LstB_Item : INotifyPropertyChanged
{
public string Title { get; set; }
private bool _checked;
public bool Checked
{
get { return _checked; }
set { _checked = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void LstB_Checklist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
txtb_Selection.Text = LstB_Checklist.SelectedItem.ToString();
}
The lisbox is populated correctly. My question is: What is the right code to get the value selected item.
Many thanks for the support
I'm afraid the question was not so clear or the answer evident, but i post an answer, it could help:
Possible answer:
var selected = LstB_Checklist.SelectedItem as LstB_Item;
txtb_Selection.Text = selected.Title;

WP7 - Call bound number on clicking Listbox item

So I have a list of objects containing a name and number bound to a listbox in XAML. The listbox displays the number fine, but I want it to call the phone number using phonecall on click. Here is the onlick code:
private void taxiListItem_Click(object sender, RoutedEventArgs e)
{
Microsoft.Phone.Tasks.PhoneCallTask phonecall = new Microsoft.Phone.Tasks.PhoneCallTask();
phonecall.PhoneNumber = "213";
phonecall.Show();
}
and here is where I define the TaxiCompany object that populates the list.
public class TaxiCompany {
public String CoName { get; set; }
public String Phone { get; set; }
public TaxiCompany(String coname, String phone) {
this.CoName = coname;
this.Phone = phone;
}
}
The phone call works fine when I hardcode the number . Now, when I set phonecall.Phonenumber = sender.getPhone() or e.Phone() or any variant of the two, its marked as an undefined method. Am I doing something fundamentally wrong here? I assume object sender or e is the list item being clicked on.
Note: the listbox in the XAML displays both the phone number and address just fine
<Button Click="taxiListItem_Click" Width ="436" Height="120">
<Button.Content>
<StackPanel Orientation="Vertical" Height=" 80">
<StackPanel Orientation="Horizontal" Height="40" Width="436">
<TextBlock Width="436" FontSize="30" Text= "{Binding CoName}" Height="40"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Height="40" Width="436">
<TextBlock Name ="PhoneNo" Width="300" FontSize="22" Text= "{Binding Phone}" Height="40"/>
</StackPanel>
</StackPanel>
</Button.Content>
</Button>
First time working with C# / Silverlight so any help would be apprecaited.
Try this. The listbox shows the taxi companies and selecting an item in the list causes the phone numbe rot try and be dialed.
Notice that it's not necessary to add buttons to the list and that it's necessary to cast the variables passed to the selection event. (Could also cast the sender to a listbox and then cast the selected item.)
xaml:
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding TaxiCompanies}" SelectionChanged="MainListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Height=" 80">
<TextBlock Width="436" FontSize="30" Text= "{Binding CoName}" Height="40"/>
<TextBlock Name ="PhoneNo" Width="300" FontSize="22" Text= "{Binding Phone}" Height="40"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
cs:
// class used for example. Another name would be more appropriate
public class ViewModel
{
public ObservableCollection<TaxiCompany> TaxiCompanies { get; private set; }
public ViewModel()
{
TaxiCompanies = new ObservableCollection<TaxiCompany>();
TaxiCompanies.Add(new TaxiCompany("AAA Cabs", "123-456-789"));
TaxiCompanies.Add(new TaxiCompany("BBB Taxis", "111234329"));
TaxiCompanies.Add(new TaxiCompany("CCC Cars", "98765432"));
}
}
public MainPage()
{
InitializeComponent();
// Set the data context of the listbox control to the sample data
DataContext = new ViewModel();
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var phonecall = new PhoneCallTask();
phonecall.PhoneNumber = ((TaxiCompany)(((object[])(e.AddedItems))[0])).Phone;
phonecall.Show();
// Reset selected index to -1 (no selection)
MainListBox.SelectedIndex = -1;
}

Resources