I have an ObservableCollection which is viewed in a custom listbox. I need the listbox to update the view according to changes applied, like inserting new feeds or removing feeds from the ObservableCollection
parts of code are available below
public class lbl
{
public ObservableCollection<feed> ModifiedItems
= new ObservableCollection<feed>();
public lbl()
{
InitializeComponent();
listBox1.ItemsSource = ModifiedItems ;
}
public void update(object sender, EventArgs e)
{
var x = ModifiedItems.Last();
listBox1.Items.Add(x);
}
}
public class feed
{
public int ID { get; set; }
public int source_id { get; set; }
public string title { get; set; }
public string source_icon { get; set; }
public string url { get; set; }
public string pudate { get; set; }
}
XAML
<ListBox x:Name="listBox1" >
<ListBox.ItemTemplate >
<DataTemplate >
<StackPanel Width="400" Margin="20" >
<Button x:Name="pic" Tag="{Binding Id}">
<Button.Template>
<ControlTemplate>
<TextBlock Text="{Binding title}" TextWrapping="Wrap" FontFamily="Arial" FontSize="28" Tag="{Binding Id}"/>
</ControlTemplate>
</Button.Template>
</Button>
<TextBlock Text="{Binding pudate}" TextWrapping="Wrap" FontSize="24"/>
<Image Source="{Binding source_icon}" Width="100" Height="60"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Note: This is not part of the code.
It gives me the error when trying to add an Item "Operation not supported on read-only collection."
I tried the solution posted here Implementing CollectionChanged and still I get the same error.
Any help please, Thanks in advance
The problem is with your update method:
public void update(object sender, EventArgs e)
{
var x = ModifiedItems.Last();
listBox1.Items.Add(x);
}
The ItemsSource of your ListBox is set to the ModifiedItems which is an ObservableCollection. Therefore if you add or remove items from this collection, the ListBox UI will update automatically. For example, to add a new items to your view simply do the following:
ModifiedItems.Add(new feed());
This is the whole point of an ObservableCollection, the view can observe it!
If, rather than adding / removing items, you are updating existing items, you will need to make feed implement INotifyPropertyChanged.
Since you're setting the ItemsSource of the ListBox, you're binding the ModifiedItems collection to it.
This means you have to modify ModifiedItems, and not the ListBox to add/remove items, which then will update accordingly.
public void update(object sender, EventArgs e)
{
var x = ModifiedItems.Last();
ModifiedItems.Items.Add(x);
}
Why you want to duplicate the last item is beyond me. But that's the change you need to do.
Related
In my xamarin.forms app, I am using Cardview's link cubeview. The cubeview is similar to carousal with a property called auto sliding. We can set the duration and it will auto slide after that time. In this cube view I am using two different templates. One for showing image and another one for video. I can show these two different views by using data template selector. Everything works fine.
Now, since the auto slide property is hard coded, even if the video or image fully loaded(I am fetching them from URL.) the view will get slided. How can bind or reference the auto duration value to the loading property of Image and video?
For Image view I am using FFImageloading
For Video view I am using Rox.Xamarin.Video
In summarise, if the image is loaded, I want to make the auto slide value to 7 seconds and if it is video I want the autoslide duration needs to be the duration of video. How can I do that? Any help is apprecited.
My cube view
<cards:CubeView
x:Name="StatusCarousal"
IsClippedToBounds="True"
SlideShowDuration="7000" // This value needs to be bind according to template
IsVerticalSwipeEnabled="True"
ItemSwiped="StatusCarousal_ItemSwiped"
PropertyChanged="StatusCarousal_PropertyChanged"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource personDataTemplateSelector}"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" >
</cards:CubeView>
Data Templates
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="Page1Template" >
<ffimageloading:CachedImage Grid.Column="0" Grid.ColumnSpan="3"
x:Name="StoryImage"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Source="{Binding Image}"
Aspect="AspectFill"
Success="CachedImage_Success"
FileWriteFinished="CachedImage_FileWriteFinished"
DownsampleToViewSize="true"
DownloadStarted="CachedImage_DownloadStarted"
>
</ffimageloading:CachedImage>
</DataTemplate>
<DataTemplate x:Key="Page2Template">
<rox:VideoView Source="{Binding VideoURl}" AutoPlay="True" FullScreen="True"
Grid.Column="0" Grid.ColumnSpan="3"
HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
>
</rox:VideoView>
</Grid>
</DataTemplate>
<local:PersonDataTemplateSelector x:Key="personDataTemplateSelector"
Page1="{StaticResource Page1Template}"
Page2="{StaticResource Page2Template}" />
</ResourceDictionary>
</ContentPage.Resources>
Model class
public partial class InnerStoreisData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string UserName { get; set; }
public ImageSource profileImage { get; set; }
public string VideoURl { get; set; }
public string Image { get; set; }
public int Type { get; set; }
}
Template selector
public class PersonDataTemplateSelector : DataTemplateSelector
{
public DataTemplate Page1 { get; set; }
public DataTemplate Page2 { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
switch (((InnerStoreisData)item).Type)
{
case 0:
return Page1;
case 1:
return Page2;
default:
return Page1;
}
}
}
I've a Picker inside a ListView with databinding:
<ListView
ItemsSource="{Binding CursorPrintParametersList}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:CursorPrintParameters">
<ViewCell>
<Grid>
<Picker
ItemsSource="{Binding LabelTypes}"
SelectedItem="{Binding SelectedLabelType}"
ItemDisplayBinding="{Binding Description}"
/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
where CursorPrintParametersList is
ObservableCollection<CursorPrintParameters> CursorPrintParametersList
and
public class CursorPrintParameters : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public List<BaseDto> LabelTypes { get; set; }
private BaseDto selectedLabelType;
public BaseDto SelectedLabelType
{
get => selectedLabelType;
set
{
if (value == null) return;
selectedLabelType = value;
RaisePropertyChanged(nameof(SelectedLabelType));
}
}
}
public class BaseDto
{
public string Code{ get; set; }
public string Description{ get; set; }
}
I'm unable to set the ItemDisplayBinding="{Binding Description}" for the Picker, getting a
Property 'Description' not found on 'CursorPrintParameters'
If i put the picker outside the ListView, everything works fine.
Any help? Thanks
i reproduce your issue in Xamarin.Forms version 3.6.0.34457
and the solution is delete below codes in DataTemplate :
x:DataType="models:CursorPrintParameters"
It is better to upgrade to the latest version if possible, as there may be some API changes
ItemDisplayBinding is the name of the property to use for the Display, not an actual binding expression
ItemDisplayBinding="Description"
I creating app for windows phone 7 (bing maps) , and I need add something like this:
when I tap on the map, I want add pushpin there, but I also need to add some information to that pushpin (like name and description)
how can i do this? or where can i find some tutorial for that ?
You could subscribe to the Tap event of the map and add Pushpins.
XAML:
<Maps:Map x:Name="Map" CredentialsProvider="Your-Creds" Tap="Map_OnTap" />
Code:
private void Map_OnTap(object sender, GestureEventArgs e)
{
GeoCoordinate location;
if (Map.TryViewportPointToLocation(e.GetPosition(Map), out location))
{
Map.Children.Add(new Pushpin
{
Location = location,
Background = new SolidColorBrush(Colors.Blue),
Content = "Hello world"
});
}
}
If you would like an MVVM approach you could have a collection of objects that you add to.
Xaml:
<Maps:Map x:Name="Map" CredentialsProvider="Your-creds"
Tap="Map_OnTap">
<Maps:MapItemsControl ItemsSource="{Binding Locations}">
<Maps:MapItemsControl.ItemTemplate>
<DataTemplate>
<Maps:Pushpin Location="{Binding Location}" Content="{Binding Name}"
Background="{StaticResource PhoneAccentBrush}">
</Maps:Pushpin>
</DataTemplate>
</Maps:MapItemsControl.ItemTemplate>
</Maps:MapItemsControl>
</Maps:Map>
Code:
public ObservableCollection<MapLocation> Locations { get; private set; }
private void Map_OnTap(object sender, GestureEventArgs e)
{
GeoCoordinate location;
if (Map.TryViewportPointToLocation(e.GetPosition(Map), out location))
{
Locations.Add(new MapLocation
{
Location = location,
Name = "Hello world"
});
}
}
public class MapLocation
{
public GeoCoordinate Location { get; set; }
public string Name { get; set; }
}
This example simply sets the DataContext of the page to be itself. A better approach is to set the DataContext of the page to be a view model with the Locations property on it.
I'm trying to bind a list box's items source to a Linq Table, the same way you would usually bind a ObservableCollection to it.
I want my list to update with the table when items are removed, added and changed.
I've implemented the INotifyPropertyChanged on the classes of which the table consists. This makes the list update the properties that my items contain, however, in order to update the list when items are added or removed, I have to programmatically rebind the ItemsSource in order to forcefully update the list.
Data context
public class LocalDatabase : DataContext
{
public static string connectionString = "Data Source=isostore:/Database.sdf";
public LocalDatabase() : base(connectionString) { }
public Table<Connection> Connections;
}
Table objects
[Table]
public class Connection : INotifyPropertyChanged
{
private string name;
private string ip;
private ushort port;
[Column(IsPrimaryKey=true, IsDbGenerated=true)]
public int ID { get; set; }
[Column]
public string Name { get { return name; } set { name = value; NotifyPropertyChanged("Name"); } }
[Column]
public string IP { get { return ip; } set { ip = value; NotifyPropertyChanged("IP"); } }
[Column]
public ushort Port { get { return port; } set { port = value; NotifyPropertyChanged("Port"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Target list
<ListBox Name="listBoxConnections" SelectionChanged="listBoxConnections_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432" Height="78">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="Edit" Click="ConnectionEdit" Tag="{Binding ID}" />
<toolkit:MenuItem Header="Delete" Click="ConnectionDelete" Tag="{Binding ID}" />
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<StackPanel Orientation="Horizontal" Margin="12,-6,12,0">
<TextBlock Text="{Binding IP}" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" />
<TextBlock Text=":" Margin="2,0,2,0" />
<TextBlock Text="{Binding Port}" Style="{StaticResource PhoneTextSubtleStyle}" Margin="0" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Current binding method
public LocalDatabase Database { get; set; }
public MainPage()
{
InitializeComponent();
Database = new LocalDatabase();
if (!Database.DatabaseExists()) Database.CreateDatabase();
listBoxConnections.ItemsSource = Database.Connections;
DataContext = this;
}
I'm afraid there might be a duplicate somewhere, but I've been searching for the last 2 days, and found no solution or similar question. Probably using the wrong queries.
So, in summary, I want to know the correct way to bind a Table to a list, with it updating upon item removal or addition, and all of that good stuff.
I'm working with Windows Phone 7.1
The best way is to separate your UI code from your DB code. Let your ListBox bind to an ObservableCollection, instead of a Table.
Try reading this:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj207023%28v=vs.105%29.aspx
I have a string array and i need to populate its value to a list box.but the values are not get in the list box. here is my code
xaml
'<ListBox Name="listBox_1" Background="White" Margin="3,131,0,0">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0,1,0,0" BorderBrush="#FFC1BCBC" Width="480">
<Grid Height="80">
<TextBlock Name="list"
Text="{Binding Path=Names}"
FontSize="36"
TextWrapping="Wrap"
Foreground="Black" FontWeight="Normal"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>'
class
'public class Names
{
//Model Class to hold Category details
public string Title { get; set; }
public string[] Names { get; set; }
public string[] Value { get; set; }
}'
xaml.cs
'protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
string[] name = ((Application.Current as App).obj_category.Names);
listBox_1.ItemsSource=name;
}'
i didnt get the names displayed in the list box.but i got the border lines that is, if the string contain 3 names i got three blank rows.why the text in it doesnot display?could any one help me .
DataContext in your ListBox is of type string[] and DataContext in each DataTemplate is a string which doesn't have a property Name.
Change Text="{Binding Path=Name}" to Text="{Binding}".