I have xamarin application where I need to pass two objects to .cs file on button click event.
I have two ListView and have button in inside the 2nd Listview items. Both ListViews will be loaded dynamically based on the JSON. Now the problem is I need to send Parent ListView datasource and second ListView data source in the button click event. currently I am able to send only one using BindingContext but I need to send two or more objects to .cs file.
<ListView x:Name="StaffListMaster_List" RowHeight="150">
<ListView.ItemTemplate>`
<ListView x:Name="Staff_Record" ItemsSource="{Binding Path=detailsobj}">`
<ListView.ItemTemplate>`
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" >
<Button Clicked="OnActionSheetCancelDeleteClicked" BorderRadius="0" BindingContext ="{Binding item}" Text="{Binding item[6]}"/>`
I want to get StaffListMaster_List data source and Staff_Record datasource inside
OnActionSheetCancelDeleteClicked(object sender, EventArgs e) {}`
First of all, don't do that. that's not what BindingContexts are for, secondly if you are responding to the event on your code behind you could just access both the DataSources using the ListView's name i.e. Staff_Record.ItemSource
If you want to use a nested Listview inside Listview, we could do that with ListView.GroupHeaderTemplate.
ParentItems class:
public class ParentItems : ObservableCollection<ChildItems>
{
public string ID { get; set; }
public string Title { get; set; }
public ParentItems(List<ChildItems> list) : base(list)
{
}
}
ChilsItems class:
public class ChildItems
{
public string ChildTitle { get; set; }
public string Description { get; set; }
}
Xaml:
<ListView HasUnevenRows="True" x:Name="listView" IsGroupingEnabled = "True">
<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell Height="40">
<StackLayout Orientation="Horizontal"
BackgroundColor="#3498DB"
VerticalOptions="FillAndExpand">
<Label Text="{Binding ID}"
VerticalOptions="Center" />
<Label Text=" "/>
<Label Text="{Binding Title}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding ChildTitle}" Detail="{Binding Description}"></TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Result:
I have uploaded on GitHub, you could download ListViewBindng folder for reference on GitHub.
https://github.com/WendyZang/Test
Finally I am able to solve the issue as follows :
Step 1 : Create IMultiValueConverter interface
Step 2 : created MultiBinding.cs class (ref : [https://gist.github.com/Keboo/0d6e42028ea9e4256715][1] )
Step 3 : Include xmlns:multi="clr-namespace:MultiBindingExample" namespace
step 4 :
<Button Command="{Binding ClearListItem}">
<Button.CommandParameter>
<multi:MultiBinding >
<Binding Source="{x:Reference control1}" Path="BindingContext"/>
<Binding Source="{x:Reference control2}" Path="BindingContext"/>
</Button.CommandParameter>
</Button>
step 4 : In view model
void ClearListViewSelectedItem( object param)
{
var commandParamList = (object[])param;
}
Final expected result would be.
Related
Basically, when a user clicks a button I would like to add a list of the names of the currently running applications with their icon next to them within a ComboBox. I know how to get my list of applications and my icons but am unsure how to link everything together. My XAML for the ComboBox currently looks like the following:
<ComboBox x:Name="dial1AppSelection" Grid.Column="3" Grid.Row="4" MinHeight="25" Height ="25" MaxHeight="35" MinWidth="120" Margin="4,0,0,0" SelectionChanged="dial1AppSelection_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Height="20" Source="???" />
<TextBlock ><Run Text="???" /></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Add to your combobox
ItemsSource="{Binding YourCollection}"
Create class for your objects:
public class MyProcess
{
public ImageSource Image { get; set; }
public string Text { get; set; }
}
Add such code to your MainWindow.xaml.cs
public ObservableCollection<MyProcess> YourCollection { get; set; }
public MainWindow()
{
InitializeComponent();
YourCollection = new ObservableCollection<MyProcess>();
YourCollection.Add(new MyProcess() { Image ="image1", Text = "txt1"});
DataContext = this;
}
Insert fields names to your xaml code:
Source="{Binding Path=Image}"
Text="{Binding Path=Text}"
This is my ListView:
<ListView ItemsSource="{Binding ModuleList}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--<Image Source="{Binding ModuleImage}" Stretch="UniformToFill"/>-->
<TextBlock Text="{Binding ModuleName}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is the code in WPF (MVVM):
public ItemListViewVM() : base()
{
ModuleList = new List<Module>();
modulLoader.LoadAllModules();
tempModulList = modulLoader.GetAllModules();
foreach (var module in tempModulList)
{
ModuleImage = module.ModuleImage;
ModuleName = module.Name;
ModuleList.Add(module);
}
}
Long story short: The List tempModulList contains Objects of type Module, which has an ImageSource Image and a string Name. Then the ModuleList gets one item after another. When I uncomment the Image in xaml, you can see it. But the TextBlock won't show up no matter what. I checked the string module.Namefor every item, it is not empty.
EDIT: Add Module Class
The Module Class just contains Name and Image:
public class Module
{
public ImageSource ModuleImage { get; set; }
public string Name { get; set; }
}
The Object gets created by deserializing a Json
The Bindings in the ItemTemplate use the properties of the data item class as their source properties. Hence you should write
Text="{Binding Name}"
instead of
Text="{Binding ModuleName}"
Unless you set the View property of a ListView (to e.g. a GridView) you could also better use a ListBox, which is the base class of ListView, and simpler:
<ListBox ItemsSource="{Binding ModuleList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ModuleImage}"/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Initializing the ModuleList property in the view model constructor would be as simple as this:
public ItemListViewVM()
{
modulLoader.LoadAllModules();
ModuleList = modulLoader.GetAllModules();
}
I am trying to access the Entry declared in a DataTemplate which is actually in a ItemTemplate in ListView, through a button click.
<StackLayout>
<Button Text="GetEntryTemplate" Clicked="Button_Clicked"/>
<ListView x:Name="listView" ItemsSource="{Binding Customer}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Entry Text="Xamarin"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
private void Button_Clicked(object sender, EventArgs e)
{
var loadedTemplate = listView.ItemTemplate.CreateContent();
var view = ((loadedTemplate as ViewCell).View as Entry).Text;
}
I have tried CreateContent(), which actually does not shows the run time changes.
Can someone help me out of this. In short I need to access the Existing Entry instance(Declared inside DataTemplate) text through the Button click.
You can use Data-Binding to set and get the text of the entry.
in xaml
<StackLayout>
<Button Text="GetEntryTemplate" Clicked="Button_Clicked"/>
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Entry TextColor="Black" Text="{Binding Content,Mode=TwoWay}"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
in your code behind
create a mode (for example my model called Data)
public class Data
{
public string Content { get; set; }
}
And in contentPage
public partial class MainPage : ContentPage
{
public ObservableCollection<Data> MySource { get; set; }
public MainPage()
{
InitializeComponent();
BindingContext = this;
MySource = new ObservableCollection<Data>()
{
new Data() {Content="Entry_1" },
};
listView.ItemsSource = MySource;
}
private void Button_Clicked(object sender, EventArgs e)
{
DisplayAlert("title", MySource[0].Content, "cancel");
}
}
I think, you have to choose another approach.
Why don't you use Binding for your Entry in ListView? If you are new to Xamarin, I would recommend you to read about MVVM pattern: link to MVVM.
You could add param like EntryText in your Customer class and get value from your ViewModel, where you will create a binded param.
Better approach would be to use view model with data binding.
But if you had to get reference to control element itself you can do this way
(items source must have at least one item in collection, added item explicitly in xaml for example):
<Button Text="GetEntryTemplate" Clicked="Button_OnClicked"/>
<ListView x:Name="listView">
<ListView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>my customer</x:String>
</x:Array>
</ListView.ItemsSource>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Entry x:Name="cellEntry" Text="Xamarin"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind:
private void Button_OnClicked(object sender, EventArgs e)
{
var cell = listView.TemplatedItems.FirstOrDefault();
var entry = (Entry)cell.FindByName("cellEntry");
DisplayAlert("My Entry", entry.Text, "Close");
}
I am making a portable Xamarin project. I have the following List in the class Stash:
public class Stash
{
public static List<Group> Groups { get; set; }
}
and a class Group:
public class Group
{
[JsonProperty(PropertyName ="Name")]
public string Name { get; set; }
[Newtonsoft.Json.JsonProperty("Id")]
public string GroupId { get; set; }
}
In another page in XAML I want to bind to a static list. I have a ListView that I want to bind to the Group List:
<ListView ItemsSource="{Binding Source={x:Static local:Stash.Groups}}"
IsGroupingEnabled="true">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" TextColor="Black"
Detail="{Binding GroupId}" DetailColor="Aqua">
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I defined the Namespace in the local in XAML:
xmlns:local="clr-namespace:Namespace"
My List is filled from the Sql Azure Database so it is not empty guys , Can anybody tell me what is wrong with my code? I cant seem to display the list on my screen , All what is displayed is this sentence Namespace.Group .
The following binding is incorrect. You don't need to
<ListView ItemsSource="{Binding Source={x:Static local:Stash.Groups}}"
You should change this to
<ListView ItemsSource="{Binding {x:Static local:Stash.Groups}"
Databinding Xamarin ListView
its working , i just removed IsGroupingEnabled="true" and it worked
<ListView ItemsSource="{Binding Source={x:Static local:Stash.Groups}}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Name}" TextColor="Black"
Detail="{Binding GroupId}" DetailColor="Aqua">
</TextCell>
</DataTemplate>
</ListView.ItemTemplate>
My model:
public class MyMessageModel
{
public string DisplaySender { get; set; }
//how does the below observable collection needs to be changed ,
//if I want to add another field to itemssource template.
//e.g. public DateTime Timestamp { get; set; }
public ObservableCollection<string> MessagesExchanged { get; set; }
public string NewMessage { get; set; }
}
Chat.xaml:
<TextBlock Name="lblFromUserName" Text="{Binding DisplaySender ,Mode=TwoWay}" Height="65" Style="{StaticResource PhoneTextNormalStyle}" FontSize="35"/>
<ItemsControl ItemsSource="{Binding Path=MessagesExchanged}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ????,Mode=TwoWay}" />
<TextBlock Text="{Binding Path=Timestamp}" HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="1"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl
<StackPanel Orientation="Horizontal" Grid.Row="1">
<TextBox Grid.Column="0" Name="txtNewMessage" Text="{Binding NewMessage,Mode=TwoWay}" Margin="0,0,0,0" Width="350"/>
<Button Grid.Column="1" Command="{Binding SendClickCommand,Mode=TwoWay}" Name="btnSend" Content="Send" Width="100" />
</StackPanel>
Chat.xaml.cs looks like below:
public class Chat: PhoneApplicationPage
{
private MyMessageViewModel _MyMessageViewModel;
public Conversation()
{
InitializeComponent();
_MyMessageViewModel = new MyMessageViewModel();
this.DataContext = _MyMessageViewModel;
}
}
My ViewModel MyMessageViewModel looks like below:
public System.Windows.Input.ICommand SendClickCommand
{
get
{
return new DelegateCommand((o) =>
{
Task.Factory.StartNew(() =>
{
//loop through the selected items and clear everything
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
try
{
//DO YOUR WORK HERE: TAKE THE NEW MESSAGE AND APPEND IT TO THE MESSAGES EXCHANGED
}
catch (Exception)
{
throw;
}
});
});
});
}
}
Now when user is in the above view called Chat.xaml (user will come to this page from Home page) i want to load it with the DisplaySender value on the top which will be fixed during the entire conversation.Value for this field be passed as navigation parameter from the home page.
And everytime user clicks on the Send button , in the SendClickCommand only update the MessagesExchanged collection by adding the new message from the txtNewMessage field and later clear this field.
I have two questions here:
When user first comes to the Chat.xaml how do i bind the data for the three fields e.g. DisplaySender(non empty value will be passed as navigation parameter ),MessagesExchanged(initially this would be empty when initiating the new conversation, otherwise it will have a non empty value from the navigation parameter) and NewMessage (initially this would be empty always).
Secondly in SendClickCommand notified property how do i take the text from txtNewMessage and update the ObservableCollection MessagesExchanged and at the end clear the value of txtNewMessage .And how to bind the values of MessagesExchanged to the datatemplate textblock field ?
I guess you are trying to pass Object of Class MyMessageModel while navigating from HomePage to ChatPage.
So define a property
private MyMessageModel currentMessageModel;
public MyMessageModel CurrentMessageModel
{
get { return currentMessageModel; }
set { currentMessageModel = value; }
}
and in OnNavigatedTo method of ChatPage set
CurrentMessageModel=PassedObjectOfMessageModel
xaml:
<TextBlock Name="lblFromUserName" Text="{Binding CurrentMessageModel.DisplaySender ,Mode=TwoWay}" Height="65" Style="{StaticResource PhoneTextNormalStyle}" FontSize="35"/>
<ItemsControl ItemsSource="{Binding Path=CurrentMessageModel.MessagesExchanged}">
//No need for data template as collection only contains string
<ItemsControl
<StackPanel Orientation="Horizontal" Grid.Row="1">
<TextBox Grid.Column="0" Name="txtNewMessage" Text="{Binding NewMessage,Mode=TwoWay}" Margin="0,0,0,0" Width="350"/>
<Button Grid.Column="1" Command="{Binding SendClickCommand,Mode=TwoWay}" Name="btnSend" Content="Send" Width="100" />
</StackPanel>
//C#
CurrentMessageModel.MessagesExchanged.Add(txtNewMessage.Text);
and you donot need any text block to show the ObservableCollection as your collection only contains string so just by setting the ItemsSource to the collection the data would be displayed.