Binding data from Linq Database using Observable Collection - WP8 - windows-phone-8

I'm saving some data in a database using linq. I have a DAO class, where I put all my CRUD methods, and I have another class where I define my table and its columns.
[Table(Name = "CONTACTS")]
public class UserContacts
{
private int _id;
[Column(Name = "ID", IsPrimaryKey = true, IsDbGenerated = true, CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ID
{
get { return _id; }
set { _id = value; }
}
private string _name;
[Column(Name = "NAME", CanBeNull = false)]
public string NAME
{
get { return _name; }
set { _name = value; }
}
private string _number;
[Column(Name = "NUMBER", CanBeNull = false)]
public string NUMBER
{
get { return _number; }
set { _number = value; }
}
}
DAO Class
public class DAOUserContacts
{
public IList<UserContacts> list = new List<UserContacts>();
public IList<UserContacts> GetData()
{
try
{
using (DataBaseContext db = new DataBaseContext(DataBaseContext.ConnectionString))
{
list = (from info in db.UserContacts orderby info.COLUMN_NAME ascending select info).ToList();
}
return list;
}
catch (Exception)
{
return null;
}
}
// Other methods
}
I'm showing all data stored in this database in a LongListSelector.
In Main.cs constructor
llsContacts.DataContext = new DAORUserContacts().GetData();
In Main.xaml
<phone:LongListSelector x:Name="llsContacts" ItemsSource="{Binding}" >
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<ListBoxItem local:TiltEffect.IsTiltEnabled="true">
<Grid Margin="0" >
<TextBlock Text="{Binding NAME}" FontFamily="Segoe WP" FontSize="28" Margin="77,0,0,0" />
<TextBlock Text="{Binding NUMBER}" FontFamily="Segoe WP Light" FontSize="17" Margin="77,33,0,0"/>
</Grid>
</ListBoxItem>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
I made a research on internet, and found about ObservableCollection, and I want to use it. I read this article http://www.codeproject.com/Articles/80555/Databinding-in-Silverlight-applications#_Toc261149245 to understand how it works, but I still have some doubts.
On this article, was created an Employee that inherits from INotifyPropertyChanged, and an Emplyees that inherits from ObservableCollection.
In my case, I want that my list (on xaml) always shows what is in database.
Is OK inheriting my UserContacts from INotifyPropertyChanged? Because this class declares a Table...
And should my DAOClass inherits from ObservableCollection? Or just my GetData() returns a ObservableCollection instead of a List?
Another thing.. there is a button that, when the user press, updates the database (search all the contacts on device, and remove from database what had been removed in phone, and add to database what had been add in phone).
Using ObservableCollection, when the search for contacts finishes, and my database is updated, should I call something to update the LongListSelector on xaml? Or after the database update, the LongListSelector is automatically updated too?
Thanks...

User viewmodel for assigning data context and assign observable collection at xaml side as binding.And viewmodel should have observable collection which you use for binding.Then if you made any changes for the collection automatically updates the longlistselector.
Every time you should change the collection according to your database changes.

Related

Trying to separate 2 items in a column for listview wpf

I am quite a newbie with wpf...any help will be appreciated.
I started a small project with a listview that displays content from MySQL. So far I had no problems except a column that has 2 items in it. I need to separate each item in its own column.
It was easy to do with date and time but this one is beyond my skills.
The display of the listview is like that (I can't post images yet):
Date |Time |CallerID |From|To |Duration
10 June 2015 |22:45|"alex" <210555555>|101 |201|234
The CallerID column contains the two values with distinct "" and <>. I need to separate as I did with Date and Time. Thanks for any help.
<ListView x:Name="Datalist" Grid.Column="1" Grid.Row="4"
ItemsSource="{Binding Path=DS}" Background="White" Foreground="Black" FontSize="16" Grid.ColumnSpan="4" FontFamily="Segoe UI" Margin="1,0,8,0">
<ListView.View>
<GridView AllowsColumnReorder="False">
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=calldate,StringFormat={}{0:dd MMMM yyyy}}"/>
<GridViewColumn Header="Time" DisplayMemberBinding="{Binding Path=calldate,StringFormat={}{0:HH:mm:ss}}"/>
<GridViewColumn Header="CallerID" DisplayMemberBinding="{Binding Path=clid}"/>
<GridViewColumn Header="From" DisplayMemberBinding="{Binding Path=src}"/>
<GridViewColumn Header="To" DisplayMemberBinding="{Binding Path=dst}"/>
<GridViewColumn Header="Duration" DisplayMemberBinding="{Binding duration}" />
</GridView>
</ListView.View>
</ListView>
private void OnLoad(object sender, RoutedEventArgs e)
{
string cs = #"server=192.168.1.123;userid=alex;
password=r3s3ll3r;database=asteriskcdrdb";
MySqlConnection conn = null;
MySqlDataReader rdr = null;
try
{
conn = new MySqlConnection(cs);
conn.Open();
string stm = "(SELECT * FROM cdr ORDER BY uniqueid DESC LIMIT 1000)";
mySqlDataAdapter = new MySqlDataAdapter(stm, cs);
mySqlDataAdapter.Fill(DS);
Datalist.ItemsSource = DS.DefaultView;
}
catch (MySqlException ex)
{
MessageBox.Show("Error: {0}", ex.ToString());
}
finally
{
if (rdr != null)
{
rdr.Close();
}
if (conn != null)
{
conn.Close();
}
}
}
Consider moving towards a more complete view model approach. Instead of binding your ItemsSource to the DataTable.DefaultView directly, you could create a collection of view models that define the presentation logic for each entry. For example, you could define a view model class such as
public class PhoneCallViewModel
{
public Date CallDate { get; set; }
public string CallerId { get; set; }
// .... Expose properties for each column
}
This will open up a lot of options for dealing with your current problem. For example, how could we split up that caller ID string? You could create another view model, such as the following
public class CallerIDViewModel
{
public string CallerName { get; set; }
public string CallerNumber { get; set; }
}
Then the PhoneCallViewModel would expose a CallerIDViewModel property. In your OnLoad method, you would create a collection of these PhoneCallViewModel objects (preferably an ObservableCollection) and bind the ItemsSource to it. Then you could simply replace your existing caller id column in your ListView with two new columns. One bound to CallerID.CallerName, and the second bound to CallerID.CallerNumber (assuming the property on PhoneCallViewModel is named CallerID).
I've left out the details of splitting the original caller ID as well as instantiating the collection, as those are separate implementation problems.
You could always create a converter and pass your clid to it with a parameter saying if you want the name of the number and it would return you the right one.
It would look like:
<GridViewColumn Header="CallerID" DisplayMemberBinding="{Binding Path=clid, Converter={StaticResource GetCallerIdConverter}, ConverterParameter='Name'}"/>
and then the converter:
public class GetCallerIdConverter : IValueConverter {
public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
string callerId = value.toString();
if (parameter == "Name")
{
//your regex to return what's in the double quotes ""
}
else
{
//your regex to return what's in the < >
}
}
Thank you all for the help, this is a great community!
So, i used a converter as maxime-tremblay-savard suggested.
class GetCalleridConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string callerId = (string)value;
Regex angleBrackets = new Regex("<[^(>)]*>");
Regex quotes = new Regex("\"([^\"]*)\"");
if (parameter.ToString() == "Number")
{
//your regex to return what's in the double quotes ""
Match angled = angleBrackets.Match(callerId);
return angled.ToString();
}
else
{
Match quot = quotes.Match(callerId);
return quot.ToString();
}
}
//And then i binded the item to xaml
.....
<Page.Resources>
<valueconverter:GetCalleridConverter x:Key="GetCallerIdConverter" />
</Page.Resources>
.......
<GridViewColumn Header="Caller Name" Width="auto" DisplayMemberBinding="{Binding Path=clid, Converter={StaticResource GetCallerIdConverter}, ConverterParameter='Name'}"/>
<GridViewColumn Header="Caller Number" Width="auto" DisplayMemberBinding="{Binding Path=clid, Converter={StaticResource GetCallerIdConverter}, ConverterParameter='Number'}"/>
//So, i got two columns with caller Name and Caller Number, only thing left to remove quotes and angle brackets....

How to refresh the data in pivot item after updating data through xaml UI?

Hello all i am working on windows phone 8 app, i am facing a issue, i am loading some data in my pivot item and if user tap a user control opens and i modify the data through user control. Data is saving into the database successfully but my pivot item is not updating immediately. i am using observable collection as following.
ObservableCollection i used like following in mypivot.xaml.cs file
ObservableCollection<MyWrapper> saveinfo = new ObservableCollection<MyWrapper>();
public ObservableCollection<MyWrapper> savedWordBankCollection
{ get { return saveinfo; } }
//MyWrapper class structure
public class MyWrapper: INotifyPropertyChanged
{
private string desc;
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyChange(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
public string Name { get; set; }
public string NameDescription
{
get { return desc; }
set
{
desc = value;
NotifyChange(new PropertyChangedEventArgs("NameDescription"));
}
}
public string NameId { get; set; }
public string NameLocId { get; set; }
}
Now as following i am loading data into my pivot item in pivot page
private void LoadWordbank()
{
List<MysecondWrapper> dbData = helper.FetchAllName(thisApp.CurrentName.Id);
if (dbData.Count != 0)
{
foreach (MySerconWrapper item in dbData)
{
saveinfo.Add(new MyWrapper { NameLocalId = item.Id.ToString(), Name= item.Name, NameDescription = item.Description, NameId = thisApp.CurrentName.Id});
}
}
}
mypivot.xaml as follwoing. i am not writing full code but how i have assigned the attributes that i am showing.
<TextBlock x:Name="wordbankStored" Grid.Column="0" Grid.Row="0" Text="{Binding Name}"/>
<Button x:Name="btnWordDescription" Grid.Row="1" Grid.Column="0" Content="{Binding NameDescription}"
Tag="{Binding}" Click="btnNameDescription_Click"/>
In above textblocks i tried:
Content="{Binding NameDescription, Mode=TwoWay}"
but it didn't work so i have removed. on btnNameDescription_Click my user control opens and i can save data in my local db of wp8 but it does not show immediately in my pivot. Please give me suggession what and how to do ? where i am wrong. need help.
I have done, first of all no need to refresh the page, observable collection can do it automatically. my observableCollection is saveInfoCollection.
there are three possiblities with the observable collection
1) deletion a item from observable collection.
2) Modifying a item in observable collection.
3) Add a item in observable collection.
Explaination
1) In first case when i will delete the item from the observable collection i will use the remove method of the observable collection like following
//savedData is my observableCollection name.
savedData.Remove(selected);
2) In second case when i will modify the item from the observable collection, here you will see the magic of the observable collection, I am taking the item object with the help of Tag property, so as i will update my database it my observable collection will automatically update.
3) In this case you can add new data object into the observable collection, and it will automatically update the observable collection.
If you are using the observableCollection than no need to refresh the page. It is the magic of ViewModel.

How to create a dictionary with multiple columns

I am working on a Windows Phone 8 app and I have some data that I need to work with. I am reading the data from a website and I have basically 4 pieces of information coming in from the website. I need to be able to do some parsing and filtering on this data before displaying it so I would like to add it to some sort of array/collection/dictionary.
Before with a C# WinForms app, I would just create a DataTable in memory that had 4 columns and just add a row for each entry. I don't think I can use DataTables with Windows Phone so I am wondering what other ways I can store this information in memory. The app doesn't store any information so I have no real need to use IsolatedStorage for any of this.
Is there some sort of Dictionary/Collection that I can use that will do something similar to a DataTable? In that it will let me store 4 pieces of information per entry?
Thanks!
If you need something simple, you could create a class which will hold the data:
public class DataFromWebSite
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public string Telephone { get; set; }
}
In the example above, I've used a strongly-typed class where each property could hold an exact value/data-type. So, Age is an integer rather than being a string for example.
Then, I'd create a collection object to hold the values:
var list = new ObservableCollection<DataFromWebSite>();
// add items to the list...
list.Add(new DataFromWebSite
{
Name = "John",
Age = 42,
Country = "Antartica",
Telephone = "941223445"
});
list.Add(new DataFromWebSite
{
Name = "Carrol",
Age = 24,
Country = "Atlantis",
Telephone = "100223445"
});
ObservableCollections work well with UIs where the list may change over time. For example, a ListBox bound to an ObservableCollection will show changes to the list when items are added or removed (but it won't show changes to the properties such as Age without implementing INotifyPropertyChange).
Then, using some of the LINQ extensions, you can do simple/readable queries:
var greaterThan30 = list.Where(d => d.Age > 30);
foreach (var item in greaterThan30)
{
Debug.WriteLine("{0}-{1}", item.Name, item.Age);
}
The above would produce a list that has only objects where the Age property is greater than 30.
Or you could use LINQ:
var greaterThan30 = from d in list
where d.Age > 30
select d;
If one of the values being returned was unique (for example an ID):
public class DataFromWebSite
{
public string Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string Telephone { get; set; }
}
You could store the list as a Dictionary<string, DataFromWebSite>:
var keyed = new Dictionary<string, DataFromWebSite>();
var d = new DataFromWebSite
{
Id = "ABC123-A";
Name = "John",
Age = 42,
Telephone = "941223445"
};
keyed.Add(d.Id, d);
// to get a value back:
if (keyed.ContainsKey("ABC123-A")) {
var d2 = keyed["ABC123-A"];
}
And, if you wanted to get the list from the Dictionary:
var list = keyed.Values.ToArray();
This is a bit of an open-ended questions for XAML (as you're really asking how use collection controls and how to do binding).
Basically, any collection would do, then use a control to bind to the various properties of elements in that collection. You could use a ListBox control, bind it to the collection, then declare an ItemTemplate within it to bind to the various properties within the elements in the collection.
<ListBox ItemsSource="{Binding Customers}" Margin="0,5,0,10">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Padding="3,0,3,0"
Text="{Binding FirstName}" FontSize="{StaticResource PhoneFontSizeSmall}"/>
<TextBlock Text="{Binding LastName}" FontSize="{StaticResource PhoneFontSizeSmall}"/>
<TextBlock Text=", " FontSize="{StaticResource PhoneFontSizeSmall}"/>
<TextBlock Text="{Binding Address}" FontSize="{StaticResource PhoneFontSizeSmall}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And you'd set the DataContext of the page (or name the ListBox and set its DataContext) to an object that has property named Customers which is the collection you want to view in a list box e.g.:
public MyPage()
{
//...
DataContext = this;
}
public List<Customer> Customers {get;set;}
I've ignored INotifyPropertyChanged, I'll leave that as an exercise to the reader.

Any way to determine when the last listboxitem comes into view?

I am new to windows phone and coming from an ios background. My question is, how can i programmatically determine when the last listboxitem comes into view? I am currently using a custom listboxitem and programmatically adding each item.
In most scenarios on Windows Phone 8 it's better to use the LongListSelector instead of the ListBox control.
Instead of loading all the items at once, the LongListSelector virtualizes its content, only loading data as needed to show in its viewport.
The ItemRealized event fires when a new item is assigned a UI container (realized). Use this event to determine if you are close to the end of the items in the datasource, then load more data.
XAML
<phone:LongListSelector x:Name='longListFlights'
ItemsSource='{Binding}'
ItemRealized='longListFlights_ItemRealized'
Height='205'
Margin='20'>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation='Horizontal'>
<TextBlock Text='{Binding FlightNumber}'
Foreground='Yellow' />
<TextBlock Text='{Binding TimeStamp}'
Margin='20,0,0,0' />
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
CODE
public partial class MainPage : PhoneApplicationPage {
private ObservableCollection<Flight> _flights =
new ObservableCollection<Flight>();
private bool _isLoadingData;
public MainPage() {
InitializeComponent();
AddFlights(60);
this.DataContext = _flights;
}
private void AddFlights(int numberFlightsToAdd) {
_isLoadingData = true;
int max = _flights.Count + numberFlightsToAdd;
for (int i = _flights.Count; i < max; i++)
{
_flights.Add(new Flight { FlightNumber = string.Format("AB-{0:D3}", i),
TimeStamp = DateTime.Now });
}
_isLoadingData = false;
}
private void longListFlights_ItemRealized(object sender,
ItemRealizationEventArgs e) {
Flight flight = e.Container.Content as Flight;
if (flight != null)
{
if (!_isLoadingData)
{
// get current count of data-source
int count = _flights.Count;
// get index of item being realized (placed in container)
int index = _flights.IndexOf(flight);
// if we are close to the end, load more data
if (count - index <= 5)
{
AddFlights(10);
}
}
Console.WriteLine(flight.FlightNumber);
}
}
}
internal class Flight {
public string FlightNumber { get; set; }
public DateTime TimeStamp { get; set; }
}
}
Screenshot

Win 8.1 SearchBox - binding suggestions

We are writing a Windows 8.1 Store App that uses the new SearchBox XAML control. It looks like the only way to get suggestions into the dropdown list as the user types is to use the SearchBoxSuggestionsRequestedEventArgs and get the SearchSuggestionCollection from the event then append the suggestions to that.
We're using Prism for WinRT and want to separate the SearchBox and it's events from the ViewModel that is getting the list of suggestion strings.
I can't find anyway of binding a list of strings to the SearchSuggestionCollection or any way of adding them programatically that doesn't involve using the event args, which is making out unit testing very complex.
Is there a way of binding/adding the suggestions that doesn't involve the event args?
Okay, so I got obsessed with this question, and here is a solution for when using the SearchBox. I've uploaded a full sample on MSDN and GitHub
In short, use the Behavior SDK and and the InvokeCommand, and then use a converter to grab whatever data you need by using the new attributes InputConvert and InputConverterParameter.
XAML:
<SearchBox SearchHistoryEnabled="False" x:Name="SearchBox" Width="500" Height="50">
<SearchBox.Resources>
<local:SearchArgsConverter x:Name="ArgsConverter"/>
</SearchBox.Resources>
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SuggestionsRequested">
<core:InvokeCommandAction
Command="{Binding SuggestionRequest}"
InputConverter="{StaticResource ArgsConverter}"
InputConverterLanguage="en-US"
InputConverterParameter="{Binding ElementName=SearchBox, Path=SearchHistoryEnabled}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</SearchBox>
Converter:
public sealed class SearchArgsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
var args = (SearchBoxSuggestionsRequestedEventArgs)value;
var displayHistory = (bool)parameter;
if (args == null) return value;
ISuggestionQuery item = new SuggestionQuery(args.Request, args.QueryText)
{
DisplayHistory = displayHistory
};
return item;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
Mainpade codebehind - of course you want this in a VM :)
public sealed partial class MainPage
{
public DelegateCommand<string> Search { get; set; }
public DelegateCommand<ISuggestionQuery> SuggestionRequest { get; set; }
public MainPage()
{
InitializeComponent();
Search = new DelegateCommand<string>(SearchedFor, o => true);
SuggestionRequest = new DelegateCommand<ISuggestionQuery>(SuggestionRequestFor, o => true);
DataContext = this;
}
private void SuggestionRequestFor(ISuggestionQuery query)
{
IEnumerable<string> filteredQuery = _data
.Where(suggestion => suggestion.StartsWith(query.QueryText,
StringComparison.CurrentCultureIgnoreCase));
query.Request.SearchSuggestionCollection.AppendQuerySuggestions(filteredQuery);
}
private readonly string[] _data = { "Banana", "Apple", "Meat", "Ham" };
private void SearchedFor(string queryText)
{
}
}
I wrote up a full walk through on my blog, but the above is all you really need :)