I am trying to make use of Oracle's continuous query notification, but in WPF MVVM with Dapper and Caliburn.Micro.
I've set up a static OracleConnector class where dapper is querying db and populates a List like this:
List<Employees> List = cnn.Query<Employees>(OracleDynamicParameters.sql, param: dyParam).AsList();
In my View I bound a DataGrid to that list:
<DataGrid VerticalScrollBarVisibility="Auto" ItemsSource="{Binding Employees}"/>
I have the below event triggered when a row is changed in database:
private void OnMyNotificaton(object sender, OracleNotificationEventArgs args)
{
MessageBox.Show("Result set has changed.", "Notification Alert",
MessageBoxButton.OK, MessageBoxImage.Exclamation);
// Append ROWID(s) to the base query to retrieve just modified row(s)
DataRow detailRow = args.Details.Rows[0];
string rowid = detailRow["Rowid"].ToString();
string sqlUpdate = sqlSelect + "where rowid = \'" + rowid + "\'";
// Append on to the sqlUpdate statement if there are additional
// updated rows
for (int i = 1; i < args.Details.Rows.Count; i++)
{
detailRow = args.Details.Rows[i];
rowid = detailRow["Rowid"].ToString();
sqlUpdate = sqlUpdate + " or rowid = \'" + rowid + "\'";
}
// Refresh changed data
using (OracleConnection con2 = new OracleConnection(constr))
{
OracleConnector.List.Clear();
OracleConnector.List = con2.Query<Employees>(sqlUpdate, new DynamicParameters()).AsList();
}
How can I refresh that row in my List and also notify VieModel about the list changes?
As you can see, I am just clearing my list and trying to query again the database with dapper and add the result to the List. The problem is only changed rows are inserted again in the list and also my DataGrid is not updating.
Oracle's example is using an OracleDataAdapter which populates a DataSet and bind it to a DataGrid like so:
// Refresh changed data
OracleConnection con2 = new OracleConnection(constr);
OracleCommand cmd2 = new OracleCommand(sqlUpdate, con2);
con2.Open();
OracleDataAdapter da2 = new OracleDataAdapter(cmd2);
da2.Fill(ds, tablename);
How can I achieve this with Dapper?
EDIT 1
I've read some tips that ObservableCollection is not notifying about changes on items inside and someone suggested to extend it like this:
public class FullyObservableCollection<T> : ObservableCollection<T>, INotifyPropertyChanged
where T : INotifyPropertyChanged
{
/// <summary>
/// Occurs when a property is changed within an item.
/// </summary>
public event EventHandler<ItemPropertyChangedEventArgs> ItemPropertyChanged;
public FullyObservableCollection() : base()
{ }
public FullyObservableCollection(List<T> list) : base(list)
{
ObserveAll();
}
public FullyObservableCollection(IEnumerable<T> enumerable) : base(enumerable)
{
ObserveAll();
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Remove ||
e.Action == NotifyCollectionChangedAction.Replace)
{
foreach (T item in e.OldItems)
item.PropertyChanged -= ChildPropertyChanged;
}
if (e.Action == NotifyCollectionChangedAction.Add ||
e.Action == NotifyCollectionChangedAction.Replace)
{
foreach (T item in e.NewItems)
item.PropertyChanged += ChildPropertyChanged;
}
base.OnCollectionChanged(e);
}
protected void OnItemPropertyChanged(ItemPropertyChangedEventArgs e)
{
ItemPropertyChanged?.Invoke(this, e);
}
protected void OnItemPropertyChanged(int index, PropertyChangedEventArgs e)
{
OnItemPropertyChanged(new ItemPropertyChangedEventArgs(index, e));
}
protected override void ClearItems()
{
foreach (T item in Items)
item.PropertyChanged -= ChildPropertyChanged;
base.ClearItems();
}
private void ObserveAll()
{
foreach (T item in Items)
item.PropertyChanged += ChildPropertyChanged;
}
private void ChildPropertyChanged(object sender, PropertyChangedEventArgs e)
{
T typedSender = (T)sender;
int i = Items.IndexOf(typedSender);
if (i < 0)
throw new ArgumentException("Received property notification from item not in collection");
OnItemPropertyChanged(i, e);
}
}
/// <summary>
/// Provides data for the <see cref="FullyObservableCollection{T}.ItemPropertyChanged"/> event.
/// </summary>
public class ItemPropertyChangedEventArgs : PropertyChangedEventArgs
{
/// <summary>
/// Gets the index in the collection for which the property change has occurred.
/// </summary>
/// <value>
/// Index in parent collection.
/// </value>
public int CollectionIndex { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
/// </summary>
/// <param name="index">The index in the collection of changed item.</param>
/// <param name="name">The name of the property that changed.</param>
public ItemPropertyChangedEventArgs(int index, string name) : base(name)
{
CollectionIndex = index;
}
/// <summary>
/// Initializes a new instance of the <see cref="ItemPropertyChangedEventArgs"/> class.
/// </summary>
/// <param name="index">The index.</param>
/// <param name="args">The <see cref="PropertyChangedEventArgs"/> instance containing the event data.</param>
public ItemPropertyChangedEventArgs(int index, PropertyChangedEventArgs args) : this(index, args.PropertyName)
{ }
}
When doing this it seems that the event is triggered when items are added/removed/changed but then again, ViewModel is not aware of this changes and View is not updating.
Here is my model class:
public class Employees : ObservableObject
{
private double _salary;
private int _employeeId;
private string firstName;
private string lastName;
private string email;
private string phoneNumber;
public int EMPLOYEE_ID {
get
{
return _employeeId;
}
set
{
_employeeId = value;
OnPropertyChanged("EMPLOYEE_ID");
}
}
public string FIRST_NAME {
get
{
return firstName;
}
set
{
firstName = value;
OnPropertyChanged("FIRST_NAME");
}
}
public string LAST_NAME
{
get
{
return lastName;
}
set
{
lastName = value;
OnPropertyChanged("LAST_NAME");
}
}
public string EMAIL
{
get
{
return email;
}
set
{
email = value;
OnPropertyChanged("EMAIL");
}
}
public string PHONE_NUMBER
{
get
{
return phoneNumber;
}
set
{
phoneNumber = value;
OnPropertyChanged("PHONE_NUMBER");
}
}
public double SALARY {
get
{
return _salary;
}
set
{
_salary = value;
OnPropertyChanged("SALARY");
}
}
}
and base model class
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (propertyName == null)
{
throw new ArgumentNullException(nameof(propertyName));
}
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The list is populated in OracleConnector.cs
public class OracleConnector
{
public static FullyObservableCollection<Employees> List;
private static string LoadConnectionString(string id = "HR")
{
return ConfigurationManager.ConnectionStrings[id].ConnectionString.ToString();
}
public static FullyObservableCollection<Employees> GetEmployeeRepositorys(string connectionString)
{
using (IDbConnection cnn = new OracleConnection(LoadConnectionString(connectionString)))
{
var dyParam = new OracleDynamicParameters();
try
{
var output = cnn.Query<Employees>(OracleDynamicParameters.sqlSelect, param: dyParam);
List = new FullyObservableCollection<Employees>(output);
}
catch (OracleException ex)
{
MessageBox.Show("Connection to database is not available.\n" + ex.Message, "Database not available", MessageBoxButton.OK, MessageBoxImage.Error);
}
return List;
}
}
}
and changes to dbs are catched in OracleDynamicParameters class
public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly DynamicParameters dynamicParameters = new DynamicParameters();
private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
public static string tablename = "Employees";
public static string constr = "User Id=hr;Password=hr;Pooling=false;Data Source=ORCL;";
public static string sqlSelect = "select employee_id, first_name, " +
"last_name, salary from employees ";
public static string sql = sqlSelect + "where employee_id < 200";
public static DataSet ds = new DataSet();
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction, object value = null, int? size = null)
{
OracleParameter oracleParameter;
if (size.HasValue)
{
oracleParameter = new OracleParameter(name, oracleDbType, size.Value, value, direction);
}
else
{
oracleParameter = new OracleParameter(name, oracleDbType, value, direction);
}
oracleParameters.Add(oracleParameter);
}
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
{
var oracleParameter = new OracleParameter(name, oracleDbType, direction);
oracleParameters.Add(oracleParameter);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
if (command is OracleCommand oracleCommand)
{
oracleCommand.AddRowid = true;
OracleDependency dep = new OracleDependency(oracleCommand);
oracleCommand.Notification.IsNotifiedOnce = false;
dep.OnChange += Dep_OnChange;
OracleDataAdapter da = new OracleDataAdapter(oracleCommand)
{
MissingSchemaAction = MissingSchemaAction.AddWithKey
};
oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
}
}
private void Dep_OnChange(object sender, OracleNotificationEventArgs args)
{
MessageBox.Show("Result set has changed.", "Notification Alert", MessageBoxButton.OK, MessageBoxImage.Exclamation);
// Append ROWID(s) to the base query to retrieve just modified row(s)
DataRow detailRow = args.Details.Rows[0];
string rowid = detailRow["Rowid"].ToString();
string sqlUpdate = sqlSelect + "where rowid = \'" + rowid + "\'";
// Append on to the sqlUpdate statement if there are additional
// updated rows
for (int i = 1; i < args.Details.Rows.Count; i++)
{
detailRow = args.Details.Rows[i];
rowid = detailRow["Rowid"].ToString();
sqlUpdate = sqlUpdate + " or rowid = \'" + rowid + "\'";
}
// Refresh changed data
OracleConnection con2 = new OracleConnection(constr);
OracleCommand cmd2 = new OracleCommand(sqlUpdate, con2);
con2.Open();
OracleDataAdapter da2 = new OracleDataAdapter(cmd2);
da2.Fill(ds, tablename);
OracleConnector.List.Clear();
OracleConnector.List = new FullyObservableCollection<Employees>(ds.Tables["Employees"].AsEnumerable().Select(p => new Employees
{
EMPLOYEE_ID = p.Field<int>("EMPLOYEE_ID"),
FIRST_NAME = p.Field<string>("FIRST_NAME"),
LAST_NAME = p.Field<string>("LAST_NAME")
}));
}
}
and finally ShellViewModel
public class ShellViewModel : Conductor<object>
{
private FullyObservableCollection<Employees> _employees;
private Employees _selectedEmployee;
public event NotifyCollectionChangedEventHandler CollectionChanged;
public Employees SelectedEmployee
{
get { return _selectedEmployee; }
set
{
_selectedEmployee = value;
NotifyOfPropertyChange(() => SelectedEmployee);
}
}
public FullyObservableCollection<Employees> Employees
{
get { return _employees; }
set
{
_employees = value;
NotifyOfPropertyChange(() => Employees);
}
}
#region Constructor
public ShellViewModel()
{
_employees = new FullyObservableCollection<Employees>(OracleConnector.GetEmployeeRepositorys("HR"));
}
#endregion
}
What am I doing wrong because I really cannot see where the issue is?
The employee list needs to be an observable list ie that tells a potential listener ie the view model binding, when it has been modified. A plain list does not do that. Change the Employees list to an ObservableCollection<Employee>. In due course you are almost certain to need to implement the IChangeNotification in your Employee class as well when properties are changed.
Related
I've got a booking system program, and one form lists the bookings already made depending on the date selected. All the times of the bookings made on the selected date were to be shown in the list box. The selected item in the list box would then populate the text boxes below with all the booking data.
However, I'm getting this error:
System.InvalidCastException: 'Specified cast is not valid.'
This is the bookingClass:
public DateTime bookingDate
{
get
{
return myDate;
}
set
{
myDate = value;
}
}
public string bookingTime
{
get
{
return myTime;
}
set
{
myTime = value;
}
}
public int bookingID
{
get
{
return myID;
}
set
{
myID = value;
}
}
public int customerID
{
get
{
return myCust;
}
set
{
myCust = value;
}
}
public string bookingTicket
{
get
{
return myTicket;
}
set
{
myTicket = value;
}
}
public int bookingQuantity
{
get
{
return myNum;
}
set
{
myNum = value;
}
}
public decimal bookingTotal
{
get
{
return myTotal;
}
set
{
myTotal = value;
}
}
//A SortedList of booking times is returned for a given Date
public SortedList GetBookingsByDate(DateTime bookingDate)
{
newCon = new System.Data.SqlClient.SqlConnection();
String firstConStr = "Data Source=.\\SQLEXPRESS;AttachDbFilename=";
String pathToDB = "F:\\Level 5\\Object Oriented Programs\\Programs\\assignmentPractice\\assignmentPractice\\assignmentDB.mdf;";
String lastConStr = "Integrated Security=True;Connect Timeout=30;User Instance=True";
newCon.ConnectionString = firstConStr + pathToDB + lastConStr;
newCon.Open();
SqlCommand cmBookList = new SqlCommand();
cmBookList.Connection = newCon;
cmBookList.CommandType = CommandType.Text;
cmBookList.CommandText = "Select bookingID, bookingTime from Booking where bookingDate = '" + bookingDate.ToLongDateString() + "'";
SqlDataReader drBookList = cmBookList.ExecuteReader();
//This is a sorted list of key/value pairs
SortedList BookList = new SortedList();
//drBookList[0] is the key (Booking ID) and drBookList[1] is the value (Booking Time)
while (drBookList.Read())
{
BookList.Add(drBookList[0], drBookList[1]);
}
drBookList.Close();
newCon.Close();
return BookList;
}
}
This is the form:
public bookingSearch()
{
InitializeComponent();
}
private SortedList BookList;
private bookingClass objBooking;
private void btnList_Click(object sender, EventArgs e)
{
lstBook.Items.Clear();
bookingClass objBooking = new bookingClass();
BookList = objBooking.GetBookingsByDate(DateTime.Parse(dtpDate.Text));
//Populate the ListBox with the Booking times
if (BookList.Count == 0)
{
lstBook.Items.Add("No Records");
return;
}
foreach (DictionaryEntry book in BookList)
{
lstBook.Items.Add(book.Value);
}
lstBook.SelectedIndex = 0;
}
private void lstBook_SelectedIndexChanged(object sender, EventArgs e)
{
if (BookList.Count > 0) //Don't process if 'No Records'
{
//Get the Booking details for a particular selected time in the list
//The SelectedIndex is used to read the Key value from the
//SortedList which holds the bookingID
objBooking.GetBookingsByDate((DateTime)BookList.GetKey(lstBook.SelectedIndex));
txtID.Text = objBooking.bookingID.ToString();
txtCust.Text = objBooking.customerID.ToString();
txtTime.Text = objBooking.bookingTime;
txtTicket.Text = objBooking.bookingTicket;
txtNum.Text = objBooking.bookingQuantity.ToString();
txtTotal.Text = objBooking.bookingTotal.ToString();
}
}
}
It's highlighting this line when I get the error:
objBooking.GetBookingsByDate((DateTime)BookList.GetKey(lstBook.SelectedIndex))
Any help is much appreciated.
I have two datatables "ResultData" and "OutputData". One of these receives results from an sql query, the other I am manually adding rows to.
ResultData gets the results from a query updates the UI appropriately. However OutputData does not. I'm going to link the entire method below. I've been stuck on this for a while, it seems to be caused due to it being async but I'm not sure how to fix it. Here is the constructor and method
class SqlInterfaceViewModel : INotifyPropertyChanged
{
private IDBQuery connection;
private string sql;
private DataTable resultData;
private DataTable outputData;
public ButtonViewModel Bvm;
private string resultStatus;
private bool queryRunning;
private string elapsedTime;
private int sqlCount;
public event PropertyChangedEventHandler PropertyChanged;
public SqlInterfaceViewModel(IDBQuery connection)
{
this.connection = connection;
outputData = new DataTable();
outputData.Columns.Add("DateTime", typeof(string));
outputData.Columns.Add("Action", typeof(string));
outputData.Columns.Add("Message", typeof(string));
outputData.Columns.Add("Duration", typeof(string));
Bvm = new ButtonViewModel(new ButtonModel(new Action(executeSql)));
OutputData.RowChanged += new DataRowChangeEventHandler(Row_Changed);
}
public bool QueryRunning
{
get { return queryRunning; }
set
{
if (value != this.queryRunning)
{
queryRunning = value;
OnPropertyChanged("QueryRunning");
}
}
}
public string Sql
{
get { return sql; }
set
{
if (sql != value)
sql = value;
OnPropertyChanged("Sql");
}
}
public DataTable ResultData
{
get { return resultData; }
set
{
if (resultData != value)
resultData = value;
OnPropertyChanged("ResultData");
}
}
public DataTable OutputData
{
get { return outputData; }
set
{
if (outputData != value)
outputData = value;
OnPropertyChanged("OutputData");
}
}
public string ResultStatus
{
get { return resultStatus; }
set
{
if (resultStatus != value)
resultStatus = value;
OnPropertyChanged("ResultStatus");
}
}
private void Row_Changed(object sender, DataRowChangeEventArgs e)
{
OnPropertyChanged("OutputData");
}
private List<string> sqlList(string sql)
{
List<string> SqlList = sql.Split(';').ToList();
return SqlList;
}
public async void executeSql()
{
foreach (string statement in sqlList(sql))
{
QueryRunning = true;
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
DateTime dateTime = DateTime.Now;
try
{
sw.Start();
if (statement.ToUpper().Contains("SELECT"))
ResultData = await connection.GetResultSetTask(statement);
else
sqlCount = await connection.ExecuteUpdate(statement);
sw.Stop();
elapsedTime = sw.Elapsed.ToString(#"hh\:mm\:ss\.ffff");
if (statement.ToUpper().Contains("SELECT"))
OutputData.Rows.Add(dateTime.ToString(), statement, ResultData.Rows.Count.ToString() + " rows selected", elapsedTime);
else if (statement.ToUpper().Contains("UPDATE"))
OutputData.Rows.Add(dateTime.ToString(), statement, sqlCount.ToString() + " rows updated successfully", elapsedTime);
else if (statement.ToUpper().Contains("INSERT"))
OutputData.Rows.Add(dateTime.ToString(), statement, sqlCount.ToString() + " rows inserted successfully", elapsedTime);
else if (statement.ToUpper().Contains("DELETE"))
OutputData.Rows.Add(dateTime.ToString(), statement, sqlCount.ToString() + " rows deleted successfully", elapsedTime);
else
OutputData.Rows.Add(dateTime.ToString(), statement, sqlCount.ToString() + " records affected", elapsedTime);
}
catch (Exception ex)
{
OutputData.Rows.Add(dateTime.ToString(), sql, sqlCount.ToString() + " records affected", elapsedTime);
}
finally
{
QueryRunning = false;
}
}
}
public void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
I have double checked my DataTable properties as well as the binding in the xaml and both are setup the same.
The executeSql method is being called via ICommand
public class ButtonViewModel {
private bool canExecute;
private ICommand clickCommand;
private ButtonModel model;
public ICommand ClickCommand { get { return clickCommand ?? (clickCommand = new CommandHandler(() => ClickAction(), canExecute)); } }
public string ImageUriString { get { return UriStringFactory.GetUriString(model.ImageUriString); } }
public string HoverText { get { return model.HoverOverText; } }
public ButtonViewModel(ButtonModel model) {
canExecute = true;
this.model = model;
}
public void ClickAction() {
model.CommandAction();
}
}
internal class CommandHandler : ICommand {
public event EventHandler CanExecuteChanged;
private readonly Action action;
private readonly bool canExecute;
public CommandHandler(Action action, bool canExecute) {
this.action = action;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter) {
return canExecute;
}
public async void Execute(object parameter) {
await Task.Run(action);
}
}
You might have gotten this by now but: It looks as though executeSql does't set OutputData as it does with ResultData. The method only mutates the state of OutputData. In that case no event will be raised. You can simply raise the change event once you've modified OutputData and your ready to update the UI. Try adding this:
public async void executeSql()
{
/**
**/
finally
{
OnPropertyChanged("OutputData");
QueryRunning = false;
}
}
}
Note: you shouldn't have any issue with this command handler being async as the current context will have been captured during the await.
I solved the issue by using Application.Current.Dispatcher.BeginInvoke
ill post my solution below
class SqlInterfaceViewModel : ViewModelBase
{
private IDBQuery connection;
private string sql;
private DataTable resultData;
private DataTable outputData;
private string resultStatus;
private bool queryRunning;
private string elapsedTime;
private int sqlCount;
private string selectedText;
private bool cancelSql;
public ICommand CommandExecute { get { return new ButtonViewModel(new ButtonModel(new Action(executeSql))).ClickCommand; } }
public ICommand CommandCancel { get { return new ButtonViewModel(new ButtonModel(new Action(Cancel))).ClickCommand; } }
public ICommand CommandClear { get { return new ButtonViewModel(new ButtonModel(new Action(Clear))).ClickCommand; } }
public event PropertyChangedEventHandler PropertyChanged;
public SqlInterfaceViewModel(IDBQuery connection){
this.connection = connection;
outputData = new DataTable();
outputData.Columns.Add("DateTime", typeof(string));
outputData.Columns.Add("Action", typeof(string));
outputData.Columns.Add("Message", typeof(string));
outputData.Columns.Add("Duration", typeof(string));
cancelSql = false;
OutputData.RowChanged += new DataRowChangeEventHandler(Row_Changed);
}
#region public properties
public bool QueryRunning
{
get { return queryRunning; }
set
{
if (value != this.queryRunning)
{
queryRunning = value;
OnPropertyChanged("QueryRunning");
}
}
}
public string Sql
{
get { return sql; }
set
{
if (sql != value)
sql = value;
OnPropertyChanged("Sql");
}
}
public string SelectedText
{
get { return selectedText; }
set
{
if (selectedText != value)
selectedText = value;
}
}
public DataTable ResultData
{
get { return resultData; }
set
{
if (resultData != value)
resultData = value;
OnPropertyChanged("ResultData");
}
}
public DataTable OutputData
{
get { return outputData; }
set
{
if (outputData != value)
outputData = value;
OnPropertyChanged("OutputData");
}
}
public string ResultStatus
{
get { return resultStatus; }
set
{
if (resultStatus != value)
resultStatus = value;
OnPropertyChanged("ResultStatus");
}
}
private void Row_Changed(object sender, DataRowChangeEventArgs e)
{
OnPropertyChanged("OutputData");
}
#endregion
private List<string> sqlList()
{
List<string> SqlList;
if (string.IsNullOrEmpty(selectedText))
SqlList = sql.Split(';').ToList();
else
SqlList = selectedText.Split(';').ToList();
return SqlList;
}
public async Task FormatOutput(string statement, string dateTime, string error)
{
statement = statement.Trim().Trim(new char[] { '\r', '\n' });
string text = string.Empty;
if (string.IsNullOrEmpty(statement) == false)
{
string substring = statement.ToUpper().Substring(0, statement.IndexOf(' '));
if (string.IsNullOrEmpty(error) != true)
text = error;
else
switch (substring)
{
case ("SELECT"):
text = ResultData.Rows.Count.ToString() + " rows selected";
break;
case ("UPDATE"):
text = sqlCount + " rows updated";
break;
case ("INSERT"):
text = sqlCount + " rows inserted";
break;
case ("DELETE"):
text = sqlCount + " rows deleted";
break;
case ("DROP"):
text = "Table dropped";
break;
case ("CREATE"):
text = "Table created";
break;
}
}
await Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
OutputData.Rows.Add(new object[] { dateTime, statement, text, elapsedTime });}));
}
public async void executeSql()
{
QueryRunning = true;
foreach (string statement in sqlList())
{
if (cancelSql == true) { cancelSql = false; break; }
string error = string.Empty;
System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
DateTime dateTime = DateTime.Now;
if (string.IsNullOrEmpty(statement) == false)
{
try
{
if (statement.ToUpper().Substring(0, statement.IndexOf(' ')).Contains("SELECT"))
ResultData = await connection.GetResultSetTask(statement);
else
sqlCount = await connection.ExecuteUpdate(statement);
}
catch (Exception ex)
{
error = ex.Message;
}
finally
{
sw.Stop();
elapsedTime = sw.Elapsed.ToString(#"hh\:mm\:ss\.ffff");
await FormatOutput(statement, dateTime.ToString(), error);
cancelSql = false;
}
}
}
QueryRunning = false;
}
public void Cancel()
{
connection.cancelQuery();
cancelSql = true;
}
public void Clear()
{ Sql = string.Empty; }
}
I’m experiencing a problem with the longlistselector witch is a bit strange... I’m reading a list asynchronously on a multi Pivot page, and if I don’t change the pivot until the resulto f the list Reading, it will create the contacts list successfuly ( in a longlistselector on the pivot item number 3 ) and when I go to that pivot the contacts list is displayed withou any problems, but when I open the Page and change the pivot before the longlistselector is created when the asychronous function returns the results and fills the longlistselector on pivot no.3 the contacts wont get updated ( when I go to pivot 3 no contacts are shown)...
I’ll post my code so you can have a clearer picture of the situation and maybe figure out what is happening.
The code is based in the PhoneToolkit LongListSelector example (buddies list)
public partial class Feeds : PhoneApplicationPage
{
bool isLoading = false;
bool loadingFilmates = true;
public Feeds()
{
InitializeComponent();
// ...
Loaded += FeedsPage_Loaded;
SystemTray.ProgressIndicator = new ProgressIndicator();
DataContext = this;
getFilmatesList();
longlistFilmates.SelectionChanged += FilmateSelectionChanged;
// ...
}
private async void getFilmatesList()
{
Feed userFilmates = await Feed.GetFilmates(App.Current.AppUser, App.Current.WSConfig, 0, "", 10000); // read feeds from webservice
Filmates = AlphaKeyGroup<StayObjectFilmates>.CreateGroups(AllFilmates.GetCurrent(userFilmates), CultureInfo.CurrentUICulture, (p) => { return p.Name; }, true);
//longlistFilmates.Visibility = System.Windows.Visibility.Collapsed;
longlistFilmates.Visibility = System.Windows.Visibility.Visible;
longlistFilmates.UseLayoutRounding = true;
pivotFeed.Visibility = System.Windows.Visibility.Collapsed;
pivotFeed.Visibility = System.Windows.Visibility.Visible;
}
}
Notice that I’ve even tried changing the Visibility property when it loads to force a re-render on the screen and it didn’t work.
This is the StayObjectFilmates class:
public class StayObjectFilmates
{
public string Img { get; private set; }
public string Name { get; private set; }
public string UserId { get; private set; }
public string Id { get; set; }
public User user { get; set; }
public StayObjectFilmates()
{
//Img = "";
//Name = "";
//Id = "";
}
public StayObjectFilmates(string p_img, string p_name, string p_Id)
{
Img = p_img;
Name = p_name;
UserId = p_Id;
}
public StayObjectFilmates(User p_user)
{
user = p_user;
}
public static string GetNameKey(StayObjectFilmates filmate)
{
char key = char.ToLower(filmate.Name[0]);
if (key < 'a' || key > 'z')
{
key = '#';
}
return key.ToString();
}
public static int CompareByName(object obj1, object obj2)
{
StayObjectFilmates p1 = (StayObjectFilmates)obj1;
StayObjectFilmates p2 = (StayObjectFilmates)obj2;
int result = p1.Name.CompareTo(p2.Name);
if (result == 0)
{
result = p1.Img.CompareTo(p2.Img);
}
return result;
}
}
This is the AllFilmates class:
public class AllFilmates : IEnumerable<StayObjectFilmates>
{
private static Dictionary<int, StayObjectFilmates> _filmateLookup;
private static AllFilmates _instance;
private Feed filmates;
// public List<StayObjectFilmates> Filmates { get; private set; }
public static AllFilmates GetCurrent(Feed p_filmates)
{
if (_instance == null)
{
_instance = new AllFilmates();
}
_instance.filmates = p_filmates;
return _instance;
}
public static AllFilmates Current
{
get
{
return _instance ?? (_instance = new AllFilmates());
}
}
public StayObjectFilmates this[int index]
{
get
{
StayObjectFilmates filmate;
_filmateLookup.TryGetValue(index, out filmate);
return filmate;
}
}
#region IEnumerable<StayObjectFilmates> Members
public IEnumerator<StayObjectFilmates> GetEnumerator()
{
EnsureData();
return _filmateLookup.Values.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
EnsureData();
return _filmateLookup.Values.GetEnumerator();
}
#endregion
private void EnsureData()
{
if (_filmateLookup == null)
{
_filmateLookup = new Dictionary<int, StayObjectFilmates>();
if (filmates != null)
{
int i = 0;
foreach (var item in filmates.itemsList)
{
User friend = item as User;
string userphoto = (friend.photo == null) ? "Images/avatar.jpg" : friend.photo;
StayObjectFilmates f = new StayObjectFilmates(userphoto, friend.fullName, i.ToString());
_filmateLookup[i] = f;
i++;
}
}
}
}
}
And this is the AlphaKeyGroup.cs file :
public class AlphaKeyGroup<T> : List<T>
{
private const string GlobeGroupKey = "\uD83C\uDF10";
/// <summary>
/// The delegate that is used to get the key information.
/// </summary>
/// <param name="item">An object of type T</param>
/// <returns>The key value to use for this object</returns>
public delegate string GetKeyDelegate(T item);
/// <summary>
/// The Key of this group.
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Public constructor.
/// </summary>
/// <param name="key">The key for this group.</param>
public AlphaKeyGroup(string key)
{
Key = key;
}
public AlphaKeyGroup(IGrouping<string, T> grouping)
{
Key = grouping.Key;
this.AddRange(grouping);
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="slg">The </param>
/// <returns>Theitems source for a LongListSelector</returns>
private static List<AlphaKeyGroup<T>> CreateGroups(SortedLocaleGrouping slg)
{
List<AlphaKeyGroup<T>> list = new List<AlphaKeyGroup<T>>();
foreach (string key in slg.GroupDisplayNames)
{
if (key == "...")
{
list.Add(new AlphaKeyGroup<T>(GlobeGroupKey));
}
else
{
list.Add(new AlphaKeyGroup<T>(key));
}
}
return list;
}
/// <summary>
/// Create a list of AlphaGroup<T> with keys set by a SortedLocaleGrouping.
/// </summary>
/// <param name="items">The items to place in the groups.</param>
/// <param name="ci">The CultureInfo to group and sort by.</param>
/// <param name="getKey">A delegate to get the key from an item.</param>
/// <param name="sort">Will sort the data if true.</param>
/// <returns>An items source for a LongListSelector</returns>
public static List<AlphaKeyGroup<T>> CreateGroups(IEnumerable<T> items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
{
SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
List<AlphaKeyGroup<T>> list = CreateGroups(slg);
foreach (T item in items)
{
int index = 0;
if (slg.SupportsPhonetics)
{
//check if your database has yomi string for item
//if it does not, then do you want to generate Yomi or ask the user for this item.
//index = slg.GetGroupIndex(getKey(Yomiof(item)));
}
else
{
index = slg.GetGroupIndex(getKey(item));
}
if (index >= 0 && index < list.Count)
{
list[index].Add(item);
}
}
if (sort)
{
foreach (AlphaKeyGroup<T> group in list)
{
group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
}
}
return list;
}
}
The FilmatesInGroup.cs and FilmatesByName.cs is the same as PeopleInGroup.cs and PeopleByFirstName.cs in the PhoneToolKit example with the names adapted.
The longlistFilmates LongListSelector Object is inserted directly inside the PivotItem no.3 ( no Grid and no ScrollView )
Thanks in advance for any help!
I want to add two lists to the box. It doesn't have a problem with adding items to the listbox, but a problem occurs when I try to click on one of the items and show a related form with details filled in to allow users to make amendments. Obviously the form didn't show, but instead an error occurs, no matter if I was try to open the form "delivery" or "pickup". The problem still occurs on one line
Error:
An unhandled exception of type 'System.InvalidCastException' occurred
in coursework2.exe
Additional information: Unable to cast object of type 'System.String'
to type 'coursework2.Pickup'.
namespace coursework2
{
public partial class MainForm : Form
{
private DeliveryForm deliveryform = new DeliveryForm();
private List<Visit> requests = new List<Visit>();
private Visit theVisit = new Visit();
private PickupForm pickupform = new PickupForm();
public void requestVisit(Visit newVisit)
{
requests.Add(newVisit);
}
public MainForm()
{
InitializeComponent();
}
private void btnNpickup_Click(object sender, EventArgs e)
{
pickupform.pickup = new Pickup();
pickupform.ShowDialog();
if (pickupform.pickup != null)
{
Pickup newPu = pickupform.pickup;
theVisit.addPick(newPu);
List<String> listOfPic = theVisit.listofPicks();
listboxVisits.Items.AddRange(listOfPic.ToArray());
}
updateList();
//this will upload details from pickup form to the list
}
private void groupBox2_Enter(object sender, EventArgs e)
{
}
private void MainForm_Load(object sender, EventArgs e)
{
}
private void btnNdelivery_Click(object sender, EventArgs e)
{
deliveryform.delivery = new Delivery();
deliveryform.ShowDialog();
if (deliveryform.delivery != null)
{
Delivery newDe = deliveryform.delivery;
theVisit.addDeliver(newDe);
List<String> listOfDel = theVisit.listofDeliver();
listboxVisits.Items.AddRange(listOfDel.ToArray());
}
updateList();
//this will upload detail of the delivery to the list
}
private void btnVall_Click(object sender, EventArgs e)
{
}
private void updateList()
{
listboxVisits.Items.Clear();
List<String> listofVis = theVisit.LisitVisits();
listboxVisits.Items.AddRange(listofVis.ToArray());
}
private void listboxVisits_SelectedIndexChanged(object sender, EventArgs e)
{
listboxVisits.FormattingEnabled = false;
int index = listboxVisits.SelectedIndex;
if (listboxVisits.SelectedItems.Count>0)
{
object object1 = listboxVisits.SelectedItems[0];
if (object1 is Delivery)
{
Delivery deliver = (Delivery)object1;
deliveryform.delivery = deliver;
deliveryform.ShowDialog();
}
else
{
Pickup pick = (Pickup)object1;// this is where error occur
pickupform.pickup = pick;
pickupform.ShowDialog();
}
}
this is the pickup class
public class Pickup
{
private string pickupname;
private string pickupaddress;
private Visit collects;
private Delivery sends;
private DateTime pdatetime;
private string dname;
private string daddress;
private DateTime dtime;
public string PickupName
{
get { return pickupname; }
set { pickupname = value; }
}
public string PickupAddress
{
get { return pickupaddress; }
set { pickupaddress = value; }
}
public string Dname
{
get { return dname; }
set { dname = value; }
}
public string Daddress
{
get { return daddress; }
set {daddress = value; }
}
public DateTime Pdatetime
{
get { return pdatetime; }
set { pdatetime = value; }
}
public DateTime Dtime
{
get { return dtime; }
set { dtime = value; }
}
public override string ToString()
{
return pickupname + " " + pickupaddress + " " + pdatetime.ToString()+" "+dname+" "+daddress+" "+dtime.ToString()+" Pickup ";
}
}
this is the visit class
public class Visit : Customer
{
private Customer requester;
private DateTime datetime;
private Delivery reciever;
private Pickup collect;
public DateTime DateTime
{
get { return datetime; }
set { datetime = value; }
}
private List<Pickup> picks = new List<Pickup>();
private List<Visit> visits = new List<Visit>();
private List<Delivery> deliver = new List<Delivery>();
public void addDeliver(Delivery de)
{
//adding new Delivery ToString the visit
deliver.Add(de);
}
public List<String> listofDeliver()
{
List<string> listofDeliver = new List<string>();
foreach (Delivery de in deliver)
{
String deAsString = de.ToString();
listofDeliver.Add(deAsString);
}
return listofDeliver;
}
public Delivery getDeliver(int index)
{
int count = 0;
foreach (Delivery de in deliver)
{
if (index == count)
return de;
count++;
}
return null;
}
public void addPick(Pickup pu)
{
picks.Add(pu);
}
public List<String> listofPicks()
{
List<string> listofPicks = new List<string>();
foreach (Pickup pu in picks)
{
String puAsString = pu.ToString();
listofPicks.Add(puAsString);
}
return listofPicks;
}
public Pickup getPicks(int index)
{
int count = 0;
foreach (Pickup pu in picks)
{
if (index == count)
return pu;
count++;
}
return null;
}
public List<String> LisitVisits()
{
List<String> visits = new List<string>();
visits.AddRange(listofDeliver());
visits.AddRange(listofPicks());
return visits;
}
public Visit getVisits(int index)
{
int count = 0;
foreach (Visit vis in visits)
{
if (index == count)
return vis;
count++;
}
return null;
}
public string VisitDetails()
{
return collect.PickupName + " " + collect.PickupAddress + " Pickup " + reciever.DeliveryName + " " + reciever.DeliveryAddress + " Delivery";
}
}
I want to load values from database in user control
I could add more user control but I cant't able to load values in user control
Code:
Add.aspx.cs
Below code is for adding more than one user control and retain the previous control values
public List<string> NoOfControls
{
get
{
return ViewState["NoOfControls"] == null ? new List<string>() : (List<string>)ViewState["NoOfControls"];
}
set
{
ViewState["NoOfControls"] = value;
}
}
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
GenerateControls();
}
private void GenerateControls()
{
foreach (string i in NoOfControls)
{
VisaUserControl ctrl = (VisaUserControl)Page.LoadControl("VisaUserControl.ascx");
ctrl.ID = i;
this.rpt1.Controls.Add(ctrl);
}
}
protected void btnAddVisa_Click(object sender, EventArgs e)
{
List<string> temp = null;
var uc = (VisaUserControl)this.LoadControl(#"VisaUserControl.ascx");
string id = Guid.NewGuid().ToString();
uc.ID = id;
temp = NoOfControls;
temp.Add(id);
NoOfControls = temp;
rpt1.Controls.Add(uc);
}
Edit.aspx.cs
Below code is for loading values from database in user control
using (OleDbCommand cmd = new OleDbCommand("Select * from visa_details where emp_id = '"+ empid +"'", DbConnection))
using (OleDbDataAdapter da = new OleDbDataAdapter(cmd))
{
OleDbDataReader DR1 = cmd.ExecuteReader();
while(DR1.Read())
{
//Here I can get values
string visaNumb = DR1[2].ToString();
string visaCountry = DR1[3].ToString();
string visaType = DR1[4].ToString();
string visaEntry = DR1[5].ToString();
string expiryDate = DR1[6].ToString();
for (int i = 0; i < y; i++)
{
VisaUserControl userconrol = (VisaUserControl)Page.LoadControl("VisaUserControl.ascx");
userconrol.TextVisaNumber = visaNumb;
userconrol.VisaCountry = visaCountry;
userconrol.VisaType = visaType;
userconrol.VisaEntry = visaEntry;
userconrol.ExpiryDate = expiryDate;
repeater1.Controls.Add(userconrol);
}
}
}
.ascx.cs
Here values are there but when it is loading all values are removed
protected void Page_Load(object sender, EventArgs e)
{
txtUser.Text = Request.Form[txtUser.UniqueID];
dropCountry.SelectedValue = Request.Form[dropCountry.UniqueID];
dropVisa.SelectedValue = Request.Form[dropVisa.UniqueID];
dropEntry.SelectedValue = Request.Form[dropEntry.UniqueID];
txtDate.Text = Request.Form[txtDate.UniqueID];
}
public string TextVisaNumber
{
get { return txtUser.Text; }
set { txtUser.Text = value; }
}
public string VisaCountry
{
get { return dropCountry.SelectedValue; }
set { dropCountry.SelectedValue = value; }
}
public string VisaType
{
get { return dropVisa.SelectedValue; }
set { dropVisa.SelectedValue = value; }
}
public string VisaEntry
{
get { return dropEntry.SelectedValue; }
set { dropEntry.SelectedValue = value; }
}
public string ExpiryDate
{
get
{
return txtDate.Text;
}
set
{
txtDate.Text = value;
}
}
Any ideas? Thanks in advance
Instead of adding the control in the page's controls collection, you should keep an set the data in some existing control's inner HTML.