Data displayed redundantly on my UITableView in monotouch - sqlite

I have problem in populating a table in monotouch using SQLite as database. My problem is it only selects the last data inserted and returns it as many as the number of data in the table selected.
ex. data=iPhone, number of data in a table = 30.
it returns the iPhone in the table 30 times.
Here is the code:
MainViewController
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
LoadToolbarButtons ();
LoadNavigationBarButtons ();
BL.Products MyProducts = new BL.Products();
List<Products> productList = new List<Products>();
POSDB.InitPOSDatabase ();
POSDB.GetAllProducts (productList, MyProducts);
tblProductList.Source = new ProductListDataSource(productList);
tblProductList.Delegate = new ProductListDelegate();
}
DataSource
public class ProductListDataSource : UITableViewSource
{
public List<Products> ProductList = new List<Products>();
public BL.Products myProducts = new BL.Products();
public ProductListDataSource(List<Products> productList):base()
{
this.ProductList = productList;
}
#region implemented abstract members of MonoTouch.UIKit.UITableViewSource
public override int RowsInSection (UITableView tableview, int section)
{
if (ProductList.Count == 0)
{
UIAlertView alert = new UIAlertView ("No Records!", "Please add some items to your table.", null, "OK", null);
alert.Show ();
}
return ProductList.Count;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
string cellIdentifier = "Cell";
UITableViewCell cellProduct = tableView.DequeueReusableCell(cellIdentifier);
if (cellProduct == null)
{
cellProduct = new UITableViewCell(UITableViewCellStyle.Value1,cellIdentifier);
}
var products = this.ProductList[indexPath.Row];
cellProduct.TextLabel.Text =string.Format("({0}) {1}", products.ProductID, products.ProductName);
cellProduct.DetailTextLabel.Text = "$" + System.Convert.ToString(products.Price);
return cellProduct;
}
#endregion
}
Is there something wrong with my codes?
Thank you in advance!

Related

Xaramin form -calling variable from other .cs file

I am doing a quiz game in Xaramin. forms. and for the score function. if the user got a correct answer, I want the score will add 1.but in my case even the give the correct answer, the score is not adding.
I am also trying to bind to the "score" variable to a label. I want to know if i put a correct code or not.
Button
private void submit_Clicked(object sender, EventArgs e)
{
string answer = this.answer.Text;
string canswer = "correct";
if (answer != null)
{
string ranswer = answer.Replace(" ", string.Empty);
if (ranswer.ToLower() == canswer)
{
DisplayAlert("GoodJob", "You got the correct answer", "OK");
bindingModel b = new bindingModel();
b.score++;
(sender as Button).IsEnabled = false;
}
else
{
DisplayAlert("Unfortunately", "Your answer is wrong", "OK");
(sender as Button).IsEnabled = false;
}
}
}
ViewModel
public class bindingModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int displayScore => Score;
public int score = 0;
void OnPropertyChanged(int score)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(score.ToString()));
}
public int Score
{
get => score;
set
{
if (score != value)
{
score = value;
OnPropertyChanged(score);
}
}
}
}
Model
<Label Text="{Binding Score}"/>
in your page constructor, keep a reference to your VM
bindingModel VM;
// this is your constructor, the name will match your page name
public MyPage()
{
InitializeComponent();
this.BindingContext = VM = new bindingModel();
...
}
then in your event handler, you do NOT need to create a new bindingModel
// update the Count on the VM
VM.Count++;
Answer
There's two things broken here:
You are re-initializing your ViewModel instead of referencing the same instance
You are passing the wrong value into PropertyChangedEventArgs
1. Referencing the View Model
You are re-initializing the ViewModel every time by calling bindingModel b = new bindingModel();
Lets initialize the ViewModel once, store it as a field, set it as the BindingContext for our ContentPage, and reference that field in submit_Clicked
public partial class QuizPage : ContentPage
{
readonly bindingModel _bindingModel;
public QuizPage()
{
_bindingModel = new bindingModel();
BindingContext = _bindingModel;
}
private async void submit_Clicked(object sender, EventArgs e)
{
string answer = this.answer.Text;
string canswer = "correct";
Button button = (Button)sender;
if (answer != null)
{
string ranswer = answer.Replace(" ", string.Empty);
if (ranswer.ToLower() == canswer)
{
await DisplayAlert("GoodJob", "You got the correct answer", "OK");
_bindingModel.score++;
button.IsEnabled = false;
}
else
{
await DisplayAlert("Unfortunately", "Your answer is wrong", "OK");
button.IsEnabled = false;
}
}
}
}
2. PropertyChangedEventArgs
You need to pass in the name of the property to PropertyChangedEventArgs.
They way PropertyChanged works is that it announces the name of the property that has changed. In this case, it needs to broadcast that the Score property has changed.
Let's use nameof(Score) to pass in the string "Score" to PropertyChangedEventArgs:
void OnScorePropertyChanged()
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(displayScore)));
}
public int Score
{
get => score;
set
{
if (score != value)
{
score = value;
OnScorePropertyChanged();
}
}
}

How can i resolve the variable i was trying to pass to a cardviewadapter that i tried to extract from sqlite cursor

The ide tells me it cannot resolve the symbols that ive put in the ProjectsCardAdapter parameters. the symbols are variables inside a try block that contains string type from cursor
I tried to initialize the string array variables outside the try block but realized i need to getCount how many rows the cursor will have in order to initialize the string arrays.
public class ProjectsFragment extends Fragment {
public ProjectsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView projectsRecycler = (RecyclerView) inflater.inflate(
R.layout.fragment_projects, container, false);
try {
SQLiteOpenHelper projectsDBhelper = new ProjectsDBhelper(inflater.getContext());
SQLiteDatabase db = projectsDBhelper.getReadableDatabase();
Cursor cursor = db.query("PROJECTS",
new String[]{"PROJ_STAGE", "PROJ_BUDGET", "PROJ_LOC", "CLIENT_NAME"}
, null
, null, null, null, null);
int rowCount = cursor.getCount();
String[] projStage = new String[rowCount];
String[] projBudget = new String[rowCount];
String[] projLoc = new String[rowCount];
String[] clientName = new String[rowCount];
int i = 0;
Float floatBudget;
if (cursor.moveToFirst()) {
projStage[i] = cursor.getString(0);
floatBudget = cursor.getFloat(1);
projLoc[i] = cursor.getString(2);
clientName[i] = cursor.getString(3);
projBudget[i] = String.format("%,.2f", floatBudget.toString());
cursor.close();
db.close();
} catch (SQLiteException e) {
Toast exceptionToast = Toast.makeText(inflater.getContext(), "Database unavailable", Toast.LENGTH_SHORT);
exceptionToast.show();
}
//This is the ProjectsCardAdapter that couldnt resolve the symbol
ProjectsCardAdapter projectsCardAdapter = new ProjectsCardAdapter(projStage, projBudget, projLoc, clientName);
projectsRecycler.setAdapter(projectsCardAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
projectsRecycler.setLayoutManager(layoutManager);
return projectsRecycler;
}
}
i wanted to test a cardview displaying a set of texts using data from SQLite but the adapter cant take the variables from cursor
Your issue is that projStage, projBudget, projLoc and clientName are being declared in the try block and therefore only have scope within the the try block.
The following would increase the scope to be within the onCreateView method :-
public class ProjectsFragment extends Fragment {
public ProjectsFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RecyclerView projectsRecycler = (RecyclerView) inflater.inflate(
R.layout.fragment_projects, container, false);
String[] projStage;
String[] projBudget;
String[] projLoc;
String[] clientName;
try {
SQLiteOpenHelper projectsDBhelper = new ProjectsDBhelper(inflater.getContext());
SQLiteDatabase db = projectsDBhelper.getReadableDatabase();
Cursor cursor = db.query("PROJECTS",
new String[]{"PROJ_STAGE", "PROJ_BUDGET", "PROJ_LOC", "CLIENT_NAME"}
, null
, null, null, null, null);
int rowCount = cursor.getCount();
projStage = new String[rowCount];
projBudget = new String[rowCount];
projLoc = new String[rowCount];
clientName = new String[rowCount];
int i = 0;
Float floatBudget;
if (cursor.moveToFirst()) {
projStage[i] = cursor.getString(0);
floatBudget = cursor.getFloat(1);
projLoc[i] = cursor.getString(2);
clientName[i] = cursor.getString(3);
projBudget[i] = String.format("%,.2f", floatBudget.toString());
cursor.close();
db.close();
} catch (SQLiteException e) {
Toast exceptionToast = Toast.makeText(inflater.getContext(), "Database unavailable", Toast.LENGTH_SHORT);
exceptionToast.show();
}
//This is the ProjectsCardAdapter that couldnt resolve the symbol
ProjectsCardAdapter projectsCardAdapter = new ProjectsCardAdapter(projStage, projBudget, projLoc, clientName);
projectsRecycler.setAdapter(projectsCardAdapter);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
projectsRecycler.setLayoutManager(layoutManager);
return projectsRecycler;
}
}
Note, this is in-principle code. The code hasn't been tested or run and therefore may contain errors.

Fill JavaFX combobox by javascript class (Nashorn)

I try to use my custom class which I have created in my script (the script is written in Nashorn) and after that I try to use this custom class to fill in as items in combobox. I know that if I want to see correct values in combobox that the class has to override method toString, but in this case I do not know much how can be overriden this method in my custom class written in Nahorn.
Below I provide my code where the variables cmbCategories is JavaFX combobox and CategoryItem which I try to use as object to fill in the items in combobox and display as category name.
I would appreciate any suggestion or ideas how can be this problem resolved.
var ClientBuilder = Java.type("javax.ws.rs.client.ClientBuilder")
var Platform = Java.type("javafx.application.Platform")
var Executors = Java.type("java.util.concurrent.Executors")
var Response = Java.type("javax.ws.rs.core.Response")
var String = Java.type("java.lang.String")
var List = Java.type("java.util.ArrayList")
Executors.newSingleThreadExecutor().execute(function () {
print("Calling for category data...")
var categoryData = ClientBuilder
.newClient()
.target(String.format("%s%s", "http://localhost:8080", "/client/action/categories"))
.request()
.get()
if(categoryData.getStatus() == Response.Status.OK.getStatusCode()) {
var categories = JSON.parse(categoryData.readEntity(String.class))
var categoryItems = new List();
for each (var category in categories) {
categoryItems.add(new CategoryItem(category.id, category.category))
}
Platform.runLater(function() {
cmbCategory.getItems().addAll(categoryItems);
});
} else {
print(categoryData.getEntity().toString());
}
})
function CategoryItem(id, name) {
this.id = id;
this.name = name;
this.toString = function () {
return this.name;
}
}
Use the ScriptEngine to retrieve an appropriate string in the cellValueFactory of the ComboBox.
Simplified example
#Override
public void start(Stage primaryStage) throws Exception {
ScriptEngineManager manager = new ScriptEngineManager();
final ScriptEngine engine = manager.getEngineByMimeType("application/javascript");
ComboBox<Object> comboBox = new ComboBox();
comboBox.setCellFactory(c -> new ListCell<Object>() {
#Override
protected void updateItem(Object item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText("");
} else {
Bindings bindings = new SimpleBindings();
bindings.put("a", item);
try {
// use script engine to retrieve text
setText(Objects.toString(engine.eval("a.name", bindings)));
} catch (ScriptException ex) {
setText("Error");
}
}
}
});
comboBox.setButtonCell(comboBox.getCellFactory().call(null));
Bindings b = new SimpleBindings();
b.put("cmbCategory", comboBox);
engine.eval("function CategoryItem(id, name) {this.id = id;this.name = name;}\n"
+"var Platform = Java.type(\"javafx.application.Platform\")\n"
+ "var categories = [new CategoryItem(1, 'a'), new CategoryItem(2, 'b'), new CategoryItem(3,'c')]\n"
+ "for each (var category in categories) {cmbCategory.getItems().add(category);}", b);
Scene scene = new Scene(new StackPane(comboBox));
primaryStage.setScene(scene);
primaryStage.show();
}
I don't see the purpose of using JavaScript for this though. Everything you do in the javascript code could be done from java code more efficiently...

WPF Data binding not happening properly in programatically generated DataGrid

In my application, I am generating a datagrid programatically and binding it with a list. I am able to see the data in the datagrid but when I edit the cell, the underlying item in the list does not get updated. Here is the code
Window dateChangeWindow = new Window();
dateChangeWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
dateChangeWindow.Owner = Application.Current.MainWindow;
dateChangeWindow.SizeToContent = SizeToContent.WidthAndHeight;
dateChangeWindow.Title = "Date Change";
StackPanel stackPanel = new StackPanel();
stackPanel.Orientation = Orientation.Vertical;
DataGrid requestGrid = new DataGrid();
requestGrid.CanUserResizeColumns = false;
requestGrid.CanUserResizeRows = false;
requestGrid.CanUserReorderColumns = false;
requestGrid.CanUserSortColumns = true;
requestGrid.AutoGenerateColumns = false;
DataGridTextColumn requestIdColumn = new DataGridTextColumn();
requestIdColumn.Header = "Request Id";
Binding idBinding = new Binding("RequestId");
idBinding.Mode = BindingMode.OneWay;
requestIdColumn.Binding = idBinding;
requestGrid.Columns.Add(requestIdColumn);
DataGridTemplateColumn startDateColumn = new DataGridTemplateColumn();
startDateColumn.Header = "Start Date";
Binding startDateBinding = new Binding("StartDate");
startDateBinding.Mode = BindingMode.TwoWay;
FrameworkElementFactory startDateFactory = new FrameworkElementFactory(typeof(DatePicker));
startDateFactory.SetBinding(DatePicker.SelectedDateProperty, startDateBinding);
DataTemplate startDateTemplate = new DataTemplate();
startDateTemplate.VisualTree = startDateFactory;
startDateColumn.CellTemplate = startDateTemplate;
startDateColumn.CellEditingTemplate = startDateTemplate;
requestGrid.Columns.Add(startDateColumn);
DataGridTemplateColumn endDateColumn = new DataGridTemplateColumn();
endDateColumn.Header = "End Date";
Binding endDateBinding = new Binding("EndDate");
endDateBinding.Mode = BindingMode.TwoWay;
FrameworkElementFactory endDateFactory = new FrameworkElementFactory(typeof(DatePicker));
endDateFactory.SetBinding(DatePicker.SelectedDateProperty, endDateBinding);
DataTemplate endDateTemplate = new DataTemplate();
endDateTemplate.VisualTree = endDateFactory;
endDateColumn.CellTemplate = endDateTemplate;
endDateColumn.CellEditingTemplate = endDateTemplate;
requestGrid.Columns.Add(endDateColumn);
requestGrid.ItemsSource = requestList;
requestGrid.Margin = new Thickness(0, 10, 0, 0);
requestGrid.HorizontalAlignment = HorizontalAlignment.Center;
stackPanel.Children.Add(requestGrid);
Button changeDoneBtn = new Button();
changeDoneBtn.Content = "Submit";
changeDoneBtn.Click += new RoutedEventHandler(changeDone_Click);
changeDoneBtn.Margin = new Thickness(0, 20, 0, 10);
changeDoneBtn.HorizontalAlignment = HorizontalAlignment.Center;
stackPanel.Children.Add(changeDoneBtn);
dateChangeWindow.Content = stackPanel;
dateChangeWindow.ShowDialog();
The ItemsSource requestList is populated before the window creation. It is declared as
IList<DateChangeWrapper> requestList = new List<DateChangeWrapper>();
And the DateChangeWrapper class looks like this
public class DateChangeWrapper : INotifyPropertyChanged
{
public DateChangeWrapper(ResponseWrapper responseWrapper)
{
RequestId = responseWrapper.RequestId;
ParentRequestId = responseWrapper.ParentRequestId;
StartDate = responseWrapper.StartDate;
EndDate = responseWrapper.EndDate;
}
private DateTime startDate;
private DateTime endDate;
public int RequestId { get; private set; }
public int ParentRequestId { get; private set; }
public DateTime StartDate
{
get { return startDate; }
set
{
startDate = value;
OnPropertyChanged("StartDate");
}
}
public DateTime EndDate
{
get { return endDate; }
set
{
endDate = value;
OnPropertyChanged("EndDate");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
As you can see from the code, I have two columns StartDate and EndDate which are displayed as DatePickers . When I debug the code, the point where window.ShowDialog is called, I see the get accessor of the Dates getting called. But when I change the value in the datepicker, the setter does not get called and my list still has the old value.
Please help me
The problem was that the changed value was not getting updated back to the underlying source because of UpdateSourceTrigger. By default, this has the value of LostFocus. I changed it to PropertyChanged and it worked ! :)
I added the following line of code to my binding
startDateBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
and similarly for EndDate

Insert The Value from 10 radio button list from .aspx page(asp.net) into a single row into the data base

I have 10 radio button list in the .aspx page (in asp.net) ,in the database one Row (name Answer)
1.In the Model Layer ,I mention this code
public class DimensionQuestion
{
public string NewCompanyName { get; set; }
public string NewSurveyName { get; set; }
public List<int> NewAnswer { get; set; }
}
2.In the Data Layer Layer,I mention this Code,
public static bool InsertNewDimAnswer(DimensionQuestion dimension)
{
bool result;
using (var helper = new DbHelper())
{
_cmdtext = "sp_InsertNewDimAnswer";
var success = new SqlParameter("#Success", SqlDbType.Bit, 1, ParameterDirection.Output, true, 0, 0,
"Result", DataRowVersion.Default, 0);
foreach (string s in dimension.NewAnswer)
{
if (s.Trim().Length > 0)
{
var parameter = new[]
{
new SqlParameter("#CompanyName", dimension.NewCompanyName),
new SqlParameter("#SurveyName", dimension.NewSurveyName),
new SqlParameter("#Answer",s ),
success,
};
helper.ExecuteScalar(_cmdtext, CommandType.StoredProcedure, parameter);
}
}
result = (bool)success.Value;
}
return result;
}
Finally in the Business Layer
private void FillObjects()
{
List Answer = new List();
Answer.Add(Convert.ToInt32(rbAnswer1.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer2.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer3.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer4.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer5.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer6.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer7.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer8.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer9.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer10.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer11.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer12.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer13.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer14.Text.Trim()));
Answer.Add(Convert.ToInt32(rbAnswer15.Text.Trim()));
_DimensionQuestion.NewAnswer = Answer;
}
And on the Button Click
protected void btnSave_Click(object sender, EventArgs e)
{
try
{
FillObjects();
if (InsertData.InsertNewDimAnswer(_DimensionQuestion)
{
ShowMessage("Information is saved");
Reset();
}
else
{
ShowMessage("Please try again");
}
}
finally
{
//_DimensionQuestion = null;
}
}
Just store it as a semi colon delimited string in the database.
When building the string loop through the radio buttons and then add ; then store the full string in the database.
Then when filling the data back in just split the string by the ; and fill the array/list with each item.

Resources