I am now creating an app, that allows user to create and retrieve data from local database. There is one column named LIKE with a default value of int 0. I have a button, but is there anyway that I can press that button then the default value of int 0 will become 1 ? Everytime I press it will add one to the default value int. How can I do that ?
Assuming your database context is set as in the tutorial I mentioned in the comment, your button click event can look like the following:
private void IncrementLikes_Click(object sender, RoutedEventArgs e)
{
//where Likes is your ObservableCollection keeping data from database
LikeItem oneAndOnly = Likes.First() as LikeItem;
//you pulled one and only LikeItem object, now you increment the likes count
oneAndOnly.LikesCount += 1;
//and here you tell the database that the changes need to be saved.
//This call can be delayed to the OnNavigatedFrom event,
// depending on your needs.
LikeDB.SubmitChanges();
}
and here is some supporting code that belongs to the .cs file of the page:
//your database context
private YourDatabaseDataContext LikeDB;
// Define an observable collection property that controls can bind to.
private ObservableCollection<LikeItem> _likes;
public ObservableCollection<LikeItem> Likes
{
get
{
return _likes;
}
set
{
if (_likes != value)
{
_likes = value;
NotifyPropertyChanged("Likes");
}
}
}
// Constructor
public MainPage()
{
InitializeComponent();
LikeDB = new YourDatabaseDataContext(YourDatabaseDataContext.DBConnectionString);
this.DataContext = this;
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Define the query to gather all of the to-do items.
var likesFromDB = from LikeItem like in LikeDB.Likes
select like;
// Execute the query and place the results into a collection.
Likes = new ObservableCollection<LikeItem>(likesFromDB);
// Call the base method.
base.OnNavigatedTo(e);
}
Using the database for just one value may be too much, so you might want to look at other alternatives, such as Windows Phone settings.
Related
In my apps, I generated a bunch of DataGridView programmaticaly. I can add/remove rows to it and retrieve all the data from it and copy the data in another DataGrid.
for instance when Im creating it
public void Example(TabControl tab)
for(int i=0;i<tab.TabCount;i++)
{
tab.TabPages.Add("Panneau " + tab.TabCount);
DataGridView panGridView = new DataGridView();
panGridView.Name = "panGridView_" + tab.TabCount;
panGridView.Location = new System.Drawing.Point(0, 0);
panGridView.RowTemplate.Height = 24;
panGridView.Size = new System.Drawing.Size(1375, 458);
panGridView.Columns.Add("id", "id");
panGridView.Columns.Add("part_code", "part_code");
panGridView.Columns[0].Width = 100;
panGridView.Columns[1].Width = 150;
panGridView.Visible = true;
panIndex.Items.Add(tab.TabCount - 1);
tab.TabPages[tab.TabCount - 1].Controls.Add(panGridView);
}
Now, I want to attach Method to this Control. I think the best way would be to attach it when I initialize the Control. For example I would attach a Method like this one
public void Action(DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
I tried a lot of this but cant figure out how do it.
Thanks
It seems to me that you want a special kind of DataGridView. You want a DataGridView with an attached method. You've learned, whenever you need a "class, very similar to another class, but with just a small thing different", you need to create a derived class, or make a composition, if you don't want to expose all methods of the base class.
class DataGridViewWithAttachedMethod : DataGridView // TODO: invent proper name
{
...
}
class MySpecialDataGridView : UserControl
{
private DataGridView dgv1;
...
}
The advantage of the first method is that users of your class (= code, not operators) have access to all DataGridView methods, so it will be very flexible to use. Disadvantage: they have access to all DataGridView methods, so they can mess up your DataGridView.
Whether you will use derivation or composition depends on how fool proof your class needs to be, in other words: do you want to expose methods that you prefer not to be used by others?
I want to attach Method to this Control.
This is not really clear. Do you want to give DataGridView an extra method, always the same one? Or do you want to Dynamically attach a method: dgv1 has another attached method than dgv2.
class DgvWithExtraMethod : ...
{
public void Action(DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
}
All instances of this dgv will have the same extra method. All you have to do is create an object of this class, and you will have this method.
However, if you want to attach different methods to instances of the class, you need a property that contains this method.
class DgvWithMethod : ...
{
public Action<DataGridViewCellMouseEventArgs> ExtraMethod {get; set;}
}
If you want your class fool proof, consider to initialize the method with a "no operation (NOP)"
private static Action<DataGridViewCellMouseEventArgs> NOP = (e) => {};
public Action<DataGridViewCellMouseEventArgs> ExtraMethod {get; set;} = NOP;
Usage:
DgvWithMethod dgv1 = new DgvWithMethod
{
ExtraMethod = (e) =>
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
}
This is the exact answer to your question. However, what I think that you want to know is: if the operator click on row 2, then I want to execute method F(), and if he clicks on row 3, I want to execute method G(), etc
If that is what you want, use visual studio designer to add an event handler on DataGridView.CellMouseClick, or if you want to reuse this class (derivation / composition) override DataGridView.OnCellMouseClick.
private void DataGridView1_CellMouseClick(Object sender,
DataGridViewCellMouseEventArgs e)
{
// find out which column is clicked
switch (e.ColumnIndex)
{
case 0: // column Id clicked
this.ProcessColumnIdClick(e);
break;
case 1: // column Name clicked
this.ProcessColumnNameClick(e);
break;
...
Take care though: if you allow column reordering, you should compare ColumnIndex with the DisplayIndex of each column.
if (e.ColumnIndex == this.columnId.DisplayIndex)
this.ProcessColumnIdClick(e);
else if (e.ColumnIndex == this.columnName.DisplayIndex)
...
Like #CurleD stated, you simply subscribe your method to specific EventHandler. So change your Action to this:
private void panGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if(e.RowIndex==2)
{
MessageBox.Show("Hello");
}
}
and then subscribe to the CellMouseClick event:
panGridView.CellMouseClick += panGridView_CellMouseClick;
I'm working on some easy log implementation. I've created some datagridview in Changelog.cs that has columns: user's ID, surname, action name ("authorization", for example), time.
(ex: 16, Brown, authorization, 10:30:00)
So I've got 2 forms: Authorization and Changelog
When user presses the button 'sign in' in Authorization form, I want to insert this data to datagridview in Changelog.
In Changelog I've got this constructor:
public Changelog(string id, string user, string operation, string date)
{
InitializeComponent();
dataGridView1.Rows[0].Cells[0].Value = id;
dataGridView1.Rows[0].Cells[1].Value = user;
dataGridView1.Rows[0].Cells[2].Value = operation;
dataGridView1.Rows[0].Cells[3].Value = date;
}
And in Authorization I've got this:
private void button1_Click(object sender, EventArgs e)
{
DateTime whenClicked = DateTime.Now;
// long authorization code
}
Doing in Authorization:
Changelog cl = new Changelog(currentUser.Id.ToString(), currentUser.Name, "authorization", whenClicked.ToString())
of course creates a new instance of Changelog, but I want to insert this data to the original one
Is there any way to implement this? Thank you!
Since Steve's answer doesn't seem to be working (quite to my surprise), maybe this will help you: The basic idea is using events, and static events at that.
So, in your Authorization Form, you'd declare an event like this:
public static event EventHandler<ActionLogEventArgs> AuthorizationEvent;
// ^^ `ActionLogEventArgs` are `EventArgs` + your id, user, operation ... props
// Trigger function
protected virtual void OnAuthorization( ActionLogEventArgs args )
{
var handler = AuthorizationEvent;
handler?.Invoke(null, args);
}
So, whenever "sign-in" is clicked, you build your ActionLogEventArgs and fire the event by calling OnAuthorization(args)
In your "Changelog" Form you register a handler for that event:
// in ctor:
Authorization.AuthorizationEvent += AddLog;
// ...
private void AddLog(object sender, ActionLogEventArgs e)
{
// Add to your DataGrid; make sure this executes on UI Thread.
}
Mind that I chose to use a static event to avoid having to have an instance.
I'd usually prefer non-static events but that would require some more effort.
Let's see if this could work for you, first.
On DataGridView
What also came to my mind was:
You might want to actually insert a new Row.
grid.Rows[0].Cells[x].Value = ... will change that row, not insert a new one.
You can retrieve the existin instance of a Form looking at the Application.OpenForms property, then use the instance present in that collection to send the new information.
But to do this you need some changes both in Changelog and Authorization.
First remove the parameters passed to Changelog constructor and create a new method that add the info to the DataGridView. So you can call this method independently from the form creation.
public Changelog()
{
InitializeComponent();
}
public void AddNewLog(string id, string user, string operation, string date)
{
dataGridView1.Rows[0].Cells[0].Value = id;
dataGridView1.Rows[0].Cells[1].Value = user;
dataGridView1.Rows[0].Cells[2].Value = operation;
dataGridView1.Rows[0].Cells[3].Value = date;
}
Now in Authorization search for the existing Changelog instance and use that instance and the AddNewLog method to add the information. Of course, if the Changelog instance is not present you can create it as before (but without passing the parameters).
private void button1_Click(object sender, EventArgs e)
{
DateTime whenClicked = DateTime.Now;
// long authorization code
Changelog cl = Application.OpenForms["Changelog"] as Changelog;
if(cl == null)
cl = new Changelog();
cl.AddNewLog(currentUser.Id.ToString(), currentUser.Name, "authorization", whenClicked.ToString());
I have this Windows Phone Page where I load data through the standard ViewModel scope.
public Profile()
{
InitializeComponent();
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
This works fine. However when I navigate to this page from some other page the data is still the same. I mean the LoadData() method should recheck updated data right? Please suggest.
EDIT:
My PersonalizedViewModelClass:
public class PersonalizationViewModel: INotifyPropertyChanged
{
public PersonalizationViewModel()
{
this.favorites = new ObservableCollection<ItemViewModel>();
this.Bar = new ObservableCollection<Bars>();
}
public ObservableCollection<ItemViewModel> favorites { get; private set; }
public ObservableCollection<Bars> Bar { get; private set; }
private string _sampleProperty = "Sample Runtime Property Value";
public string SampleProperty
{
get
{
return _sampleProperty;
}
set
{
if (value != _sampleProperty)
{
_sampleProperty = value;
NotifyPropertyChanged("SampleProperty");
}
}
}
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a few ItemViewModel objects into the Items collection.
/// </summary>
public async void LoadData()
{
favorites.Clear();
try
{
var query = ParseObject.GetQuery("Favorite")
.WhereEqualTo("user", ParseUser.CurrentUser.Username);
IEnumerable<ParseObject> results = await query.FindAsync();
this.favorites.Clear();
foreach (ParseObject result in results)
{
string venue = result.Get<string>("venue");
string address = result.Get<string>("address");
string likes = result.Get<string>("likes");
string price = result.Get<string>("price");
string contact = result.Get<string>("contact");
this.favorites.Add(new ItemViewModel { LineOne=venue, LineTwo=address, LineThree=likes, Rating="", Hours="", Contact=contact, Price=price, Latitude="", Longitude="" });
}
if (favorites.Count == 0)
{
// emailPanorama.DefaultItem = emailPanorama.Items[1];
MessageBox.Show("You do not have any saved cafes. Long press a cafe in main menu to save it.");
}
}
catch (Exception exc)
{
MessageBox.Show("Data could not be fetched!", "Error", MessageBoxButton.OK);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Implementation of PersonalizedViewModel:
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
await App.PersonalizedViewModel.LoadData();
user_tb.Text = ParseUser.CurrentUser.Username;
if (NavigationContext.QueryString.ContainsKey("item"))
{
var index = NavigationContext.QueryString["item"];
var indexParsed = int.Parse(index);
mypivot.SelectedIndex = indexParsed;
}
if (NavigationService.BackStack.Any())
{
var length = NavigationService.BackStack.Count() - 1;
var i = 0;
while (i < length)
{
NavigationService.RemoveBackEntry();
i++;
}
}
}
I don't see the problem, however, I think you need to narrow in on the problem.
First off, you are calling LoadData from 2 places. 1 from MainPage_Load and 1 from OnNavigatedTo. In MainPage_Load it is conditional and in OnNavigatedTo it is always being called. I suggest that you get to a single path through the code instead of 2 so that you don't get different experiences. I personally recommend (without knowing all the details) that you call load data from OnNavigatedTo instead of MainPage_Load. If you want to do it conditionally that is fine but if you are loading the data from memory, it really is unnecessary as you won't improve performance anymore than a few milliseconds. Also, if you are not loading from memory, you may not want to load it conditionally because the underlying data may have changed. In either case, the choice to load data or not should be moved out of the view and into the data layer (but that is for another post).
Once you have a single path chosen (i.e. calling LoadData from MainPage_Load or OnNavigatedTo) you should use your debugger. Put a break point in LoadData method and if it is being called appropriately, then your problem is more specific than your posted question. Here are some questions to think about (you may want to start from the last question and work your way backward)
Questions:
Is LoadData being called appropriately?
Does ParseObject have the correct data?
Is the ParseUser...UserName set properly?
Is the foreach being executed the proper # of times (i.e. does the result of your query have the right # of items?)
Couple Code Tips completely unrelated to this problem:
Single Path through code. Don't call LoadData from more than one place.
Don't call favorites.clear() twice in the same method. (it is called twice in LoadData)
Consistent naming. favorites is lowercase but Bar is upper case.
User proper data types. On your ItemViewModel you have Hours, Latitude, and Longitude. You have them as strings. These clearly are not strings. Also, you should not set them to empty. Empty means they have been set to a value. Emtpy is a valid value. Null means not set. To keep your objects clean and accurate you want to be accurate in how you set things and then deal appropriately with the impact. If you really really want them to be initialized to empty strings, then at least do it in the constructor of ItemViewModel so that every caller doesn't have to know how to initialize every property. I guarantee this is leading to buggy code if you continue using this practice.
Please take the comments as constructive criticism not criticism. I know many people don't like to hear these things but the teams I lead write bugs until they start following these types of guidelines.
Good luck,
Tom
Instead of defining this
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
into constructor i.e. Profile I would suggest remove this code from Constructor and add it into your OnNavigatedTo. so the data will load after navigation
Your OnNavigatedTo Method looks like follows
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
Might be your problem will solve.
Edit
Try this query
var results = (from find in ParseObject.GetQuery("Favorite").WhereEqualTo("user", ParseUser.CurrentUser.Username) select find);
Tried this:
var query = from favorite in ParseObject.GetQuery("Favorite")
where favorite.Get<string>("user") == ParseUser.CurrentUser.Username
select favorite;
IEnumerable<ParseObject> results = await query.FindAsync();
I had a similar Problem.All u want to do here is generate a new instance of the Page.U can do this in two Ways.
One Way is by forcing a GUID along with Page Navigation URI that will create a New Instance of the Page and your Load Data() will work.
NavigationService.Navigate(new Uri(String.Format("/MainPage.xaml?item={0}", Guid.NewGuid().ToString()), UriKind.RelativeOrAbsolute));
The Second Way to implement that Part of your Page in a User Control .Like create a User Control for Load Data() and put it in constructor.It will generate a new Instance everytime you load the Page.
If the problem persists in the front end,you can try this.
1.have you mentioned the below attribute in your xaml page?
<UserControl Loaded="MainPage_Loaded">
So that every time the page loads the data will get loaded on to the page.
2.The data must exist, if you have no problem in the code behind as it is a WPF application and not a web page.
Hope you find it useful.
Two changes required..
Remove the this.Loaded from OnNavigatedTo. That may not be required.
Second move the LoadData to OnNavigatedTo method
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
App.PersonalizedViewModel.favorites.Clear();
DataContext = App.PersonalizedViewModel;
// this.Loaded += new RoutedEventHandler(MainPage_Loaded);
if (!App.PersonalizedViewModel.IsDataLoaded)
{
App.PersonalizedViewModel.LoadData();
}
}
For the purpose of debugging, you can remove the line if (!App.PersonalizedViewModel.IsDataLoaded) and try.
I have the following snippet of code that allows me to pull the properties from an object in my list and assign them to variables in other forms. However, I need to be able to pull the data from my variables in the other form and use those to set the properties of the given object.
My class Account is used to populate my list accounts. On my next form AccountMenu I have a class Variables1 that contains accessible variables that are used throughout the rest of my forms to keep track of the checking balance and saving balance. When logging off from the AccountMenu, I want to be able to pass the values from Variables1 to the account that was initially used.
I know how to pass variables from one form to another, but I'm not really sure how to update the form automatically, without a button, on the original form. Thus, the solution that I see is that I have a button on my AccountMenu form that "logs" the user out, via this.close(); Additionally, I guessed that under that button, I need to have some code that assigns the variables as properties to the object. I'm just not sure how I can access the set properties of the object, since it is dynamically called with the code below.
Can someone help me figure out what I need to do? Below is some of the relevant code so that you can see how I have things set up. I am just not sure how to access "matches" from the other form in order to update that specific object properties. Thank you, anyone, who can help!
//variable that will be used to check textbox1.Text
string stringToCheck;
//array of class Account
List<Account> accounts = new List<Account>();
public MainMenu()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//set value to user's input
stringToCheck = textBox1.Text;
//set a var that only returns a value if the .Name already exists
var matches = accounts.FirstOrDefault(p => p.Name == stringToCheck);
//check through each element of the array
if (matches == null)
{
accounts.Add(new Account(stringToCheck));
textBox1.Text = "";
label3.Visible = true;
}
else if (matches != null)
{
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
this.Hide();
acctMenu.Show();
}
}
As per my understanding I think what you required is kind of trigger on your parent form that needs to be called from your child application.
If that is what you required than you can go with defining an event on your AccountMenu form. and register this event from your Accounts form.
Than simply raise this event from your AccountMenu subform.
Deletegates and Events are really works like magic :)
Let me show you some code how to do this.
Code required in AccountMenu window:
public delegate void PassDataToAccounts(string result);
public event PassDataToAccounts OnPassDataToAccount;
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (OnPassDataToAccount != null)
OnPassDataToAccount("result");
base.OnClosing(e);
}
Code required in Accounts window button1_Click event where the AccountMenu will open:
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
acctMenu..OnPassDataToAccount += childwindow_OnPassDataToAccount;
this.Hide();
acctMenu.Show();
}
void childwindow_OnPassDataToAccount(string result)
{
if (result == "result")
{
// Processing required on your parent window can be caried out here
//Variables1 can be processed directly here.
}
}
I have a simple question in asp.net.
I want to know if it is possible to get data from controls in my user control directly . I want to do it without using Session variable,Viewstate ...
EDIT: I now use the method of declaring public variables in the UC.
Here is a part of Page_load from my parent page:
this.plan_action = (UCPlan)Page.LoadControl("~/Association/UCPlan.ascx");
PlaceHolder1.Controls.Add(this.plan_action);
if (this.plan_action.Validate == true)
{
CheckBox1.Checked = true;
//String référence = Session["liste_action"].ToString();
for (int i = 0; i < this.plan_action.List1.Count; i++)
{
Label8.Text += this.plan_action.List1[i].Référence + "/";
//Label8.Text += "/";
}
}
but my variable validate stay to false.
Here is the code where I change the value of the validate variable with it declaration:
private bool validate;
public bool Validate
{
get { return validate; }
set { validate = value; }
}
protected void Button2_Click(object sender, EventArgs e)
{
//myCommand.Connection = myConnection;
//Session["liste_action"] = this.List;
this.Validate = true;
//Response.Redirect("../Risques_folder/AjouterRisque.aspx");
}
Thank you for your help,
Quentin
UPDATE due to new information
You need to learn about the sequence of events in ASP.NET.
The Load of the page happens a long time before the Click handler of Button2 in your UserControl... so the Validate property is always going to be set to false.
You have two obvious options (as I see it)...
Keep the creation of the UserControl in your Page_Load (or preferably, move it to your Page_Init, as this is normally the most appropriate place for it). Then place your check for the Validate property in a Page_PreRender.
Or, create an Event in your UserControl, Raise that event on the click of Button2, and handle the event in the Page.
ANOTHER UPDATE
For the 2nd of the two options above, in your UserControl class have the following...
public delegate void ButtonClickedDelegate(object sender, EventArgs e);
public event ButtonClickedDelegate ButtonClicked;
In the Button2_Click method of the UserControl (after setting the this.Validate = true;) call...
ButtonClickedDelegate(sender, e);
In the Page_Init of the Page, put something like...
ctrl1.ButtonClicked += new UCPlan.ButtonClickedDelegate(ctrl1_ButtonClicked);
And then have a new method called something like
void ctrl1_ButtonClicked(object sender, EventArgs e)
{
if (ctrl1.Validate)
{
...
}
}
Remember, as you control the delegate you can pass whatever information you want, including an entire class. So instead of calling the Validate property, create a new instance of the class you want, and pass that as a delegate parameter.
You can find more information on delegates and events on MSDN.
ORIGINAL ANSWER
Unless I've missed something, this is a very simple ASP.NET concept...
You can create properties and/or methods.
For example, as a property...
public string MyProperty
{
get { return "My Property Value"; }
}
Or as a method
public string MyMethod()
{
return "My Method Value";
}
If you're talking about passing the values between the UserControl and the ASP.NET Page that contains it, then in your Page, you can simply call the property or method. If your control was called (for example) myCtrl, then you can something like...
string prop = myCtrl.MyProperty;
string meth = myCtrl.MyMethod();
(On the back of the great comment from AHMED EL-HAROUNY)
If you're talking about passing the values to the client side page, then you can use the same properties / methods directly in the HTML markup. However, in this case, the properties / method can be declared as protected rather than public
For instance, to display the value...
<%=MyProperty%>
Or
<%=MyMethod()%>
Or if you're going to use the value in javascript, something like...
var myProp = "<%=MyProperty%>";
Yes That is possible, But exposing the controls in the UserControl as Public.