I have tow form,ListFrom, and DetailForm
In the ListForm I have a devexpress grid and some button(add, delete, edit)
In the DetailForm I have some textboxes and some button(save,delete,next,previous)
well I have to senario
1 - I open the ListForm and I click on a product to modify it a got the DetailForm opened, I make some modification and I save,then i should have my grid in the ListForm refreshed with the new value.for this I have this code
In the ListFrom
FrmProduit frm = new FrmProduit(monProduit.Id) { MdiParent = this.MdiParent};
frm.updateDataInGridView += new System.Action(refereshGridView);
frm.Show();
in the detailform
if (updateDataInGridView != null)
updateDataInGridView();
well in this scenario everything is OK
second scenario
If I open the detailFrom,and after that I open the listForm, I make some change in the detailFrom and I click save updateDataInGridView in this case is null and then the grid is not refreshed
anyone have suggestion?
I would create a shared BindingSource that both forms would use to show data. If any item is changed in BindingSource it takes care to notify all controls bind to it and so it would refresh grid automatically.
Second approach is to make refereshGridView method public and in DetailForm on save click do this:
var lists = Application.OpenForms.OfType<Form>().Where(x => x.GetType() == typeof(ListFrom));
foreach (var listform in lists)
{
listform.refereshGridView();
}
I did not use FirstOrDefault as maybe there is more than one listform opened.
EDIT about Binding Source
Here is quite good tutorial so please take a look.
Below is a fast-written far from best example of stretch I did:
internal static class DataSources
{
private static BindingSource bs;
public static BindingSource CerateDataSource(List<object> yourObjects)
{
bs = new BindingSource();
bs.DataSource = yourObjects;
}
public static BindingSource GetDataSource()
{
return bs;
}
public static void Reset()
{
bs.ResetBindings(false);
}
}
and then in your listview
dataGridView1.DataSource = DataSources.GetData();
and in detailsview where you are editing one of the objects from BindingSource on save you would have to call: DataSources.Reset();. This is just a markup, but hopefully you get the idea :).
You must always be sure you are referring to the current instance of detailform, thus declare on your listForm
detailform obj = (detailform)Application.OpenForms["detailform"];
And every time you call detailform from listForm do it by obj e.g:
obj.Show()
Related
This question already has answers here:
Communicate between two windows forms in C#
(12 answers)
Closed 2 years ago.
To masters out there, I'm having problem with passing values 2 user controls within a form. I have usercontrol A which has combobox and a button and control B that has a datagridview. Now I want to display the data in User Control B which is in the datagridview. How can I pass the data from UCA to UCB?
Here's the data I want to pass:
So in User Control A when I clicked the button named Generate, it will fill the datagridview in User Control B with the data generated in the GetConvo() below.
public DataTable GetConvo() {
DataTable table = new DataTable();
table.Columns.Add("ConvoUser", typeof(Object));
table.Columns.Add("Message", typeof(Object));
table.Columns.Add("Date", typeof(Object));
var _data = from data in User.GetMatchConvo(comboBox3.SelectedValue.ToString())
select new {
convoUser = data.actor_id,
convoMessage = data.message,
convoDate = data.creation_timestamp
};
foreach (var data in _data) {
table.Rows.Add(data.convoUser, data.convoMessage, data.convoDate);
}
//dataGridView1.AllowUserToAddRows = false;
//dataGridView1.AllowUserToDeleteRows = false;
return table;
}
private UserInterface User = new UserData();
UserControlA knows/should know UserControlB?
Then create a property of type of UserControlB in UserControlA, then whenever you want to pass data to UserControlB, use the instance which you have in UserControlB property.
Which is which? Right, Maybe the BindingNavigator and BindingSource example is a bit clearer:
public class BindingNavigator
{
Public BindingSource BindingSource { get; set; }
public int Position
{
get {return BindingSource?.Position ?? -1};
set {if(BindingSource!=null) BindingSource.Position = value;}
}
}
Then when you dropped an instance of the BindingNavigator and an instance of the BindingSource on the form, set BindingSource property of the BindingNavigator to bindingSource1.
UserControlA doesn't/shouldn't know UserControlB?
Use events. It's the most natural way. Every day you are using it, like TextChanged, SelectedIndexChanged, and so on. Time to create one for your user control.
In fact you need to raise event in UserControlA, then on the form, when you dropped an instance of UserControlA and an instance of UserComtrolB, handle UserControlA event and set UserControlB property.
To make it a bit clearer, again with BindingNavigator and BindingSource:
public class BindingNavigator
{
public event EventHanlder MovingNext;
public void MoveToNextRecord()
{
MovingNext?.Invoke(this, EventArgs.Empty);
}
}
Then when you dropped an instance of the BindingNavigator and an instance of the BindingSource on the form, handle MovingNext event of bindingNavigator1 and set position of the bindingSource1:
bindingNavigator1.MovingNext += (obj, args) => {
bindingSource1.Position +=1;
};
Want to learn more about events? Take a look at the following documentations:
Handling and raising events
Standard .NET event pattern
you can create a static variable in usercontrol and pass data to this variable
in UserControl A or B Create a variable
public static string info = string.empty;
and before you open usercontrol you must pass data to variable
UsercontrolA.info = "hello";
new UsercontrolA();
UPDATE
create a static instance of usercontrol in UsercontrolA
public static internal UsercontrolA uc;
now in you ctor
public UsercontrolA(){
InitializeComponent();
uc = this;
}
You now need a function to perform the display operation
public void showData(){
// your display codes
messagebox.show(info);
}
And at the end, after you click button, also call the display function.
UsercontrolA.info = "hello";
new UsercontrolA();
UsercontrolA.us.showData();
I didn't test the codes but it definitely should work
I am a not experienced programmer, just a rookie enthusiast.
I have a webForm where I add items to a drop-down list.
There is another webform that contains another drop-down list, I want this second "ddl" to display the items I added to the "first ddl".
After not succeeding with public properties, I tried to get this accomplished in the most straight fashion:
In designer.cs change the first "ddl" from protected global to public.
On the second webForm I wrote:
WebForm3 wf_ConfigurationPage = new WebForm3();
And a short function with these lines:
ddl_ingenieros.DataSource = wf_ConfigurationPage.ddl_Engineers;
ddl_ingenieros.DataBind();
I am calling the function from PageLoad but unfortunately the "ddl" is not showing the items from its "DataSource ddl".
Also, when I switch pages, the items I added to the original "ddl" just disappear.
Can you help me get these 2 issues resolved?
I managed to get something similiar done for a gridview as follows:
On the webform where the original gridview is located:
static DataSet DS;
static DataTable tableRequests;
/* -------------- Public Properties ---------------- */
public DataSet currentList //Allows access from other pages.
{
get {
return DS;
}
}
public DataTable currentTable {
get {
return tableRequests;
}
}
On the second webForm I wanted to show the gridview:
WebForm1 wf_ActiveReq = new WebForm1();
Then a short function that I call from PageLoad, which has these lines:
gv_results.DataSource = wf_ActiveReq.currentList;
gv_results.DataBind();
I was unable to do the same with the ddls because unlike the DataSet and the Data Table, the ddl was created from designer view, when I tried to declared them in the "code behind" of the webForm where the "original" ddl exists I got an error about the object being duplicate, which makes sense.
Thanks for your time
#Erkaner
In first webForm:
static List<string> myItems = new List<string>();
protected void btn_add_Click(object sender, EventArgs e)
{
if (Session["myItems"] != null)
{
myItems = (List<string>) Session["myItems"];
}
myItems.Add(txt_newAdmin.Text);
ddl_Engineers.DataSource = myItems;
ddl_Engineers.DataBind();
txt_newAdmin.Text = "";
}
In second webForm, I wrote a function I call from pageLoad:
private void pull_engineersList()
{
ddl_ingenieros.DataSource = Session["myItems"];
ddl_ingenieros.DataBind();
}
Thanks again!
Why not use Session :
In the first page:
Session["myddlstore"] = myFirstDDL.DataSource;
and in the second page
mySecondDDL.DataSource = Session["myddlstore"];
mySecondDDL.DataBind();
UPDATE
If the dropdowlinst items are added by the user, then you can implement something like this in the button click that adds item to the dropdownlist:
List<string> myitems = new List<string> ();
if(Session["myitems"] != null)
{
myitems = (List<string>) Session["myitems"];
}
myitems.Add(txt_NewItem.Text);
myFirstDDL.DataSource = myitems;
myFirstDDL.DataBind();
and, similarly. in the second page
mySecondDDL.DataSource = Session["myitems"];
mySecondDDL.DataBind();
Session["myitems"] = myitems;
If you store a more complex object in dropdownlist, I would define a class that represents the complex object, and still use the approach described above (List<ObjectType>).
A brief intro
The program runs a test on the machines. Then a dialogBox appears asking the user if all the machines worked correctly. If they say no another window appears with the dataGridView asking which machines failed through the checkBox method. This then sets the status to the ERROR status so the program can continue running while ignoring the machines with errors.
I have this class with the two properties
public class ASM
{
public byte DeviceID
public ASMStatus Status
}
I put this in a list
list<ASM001.ASM> ASMs = new list();
Now I want to add this list to a bindingSource in my dataGridView but only those whose Status equals ASMStatus.IDLE
I thought about just creating those that have idle into another list and attaching that to the binding list, however, the dataGridView also has a checkBox column that determines if the status needs to be changed to ASMStatus.ERROR
public partial class FailedMessageBox : Form
{
public FailedMessageBox()
{
InitializeComponent();
DataGridViewCheckBoxColumn col1 = new DataGridViewCheckBoxColumn();
col1.HeaderText = "Device Failed";
dataGridView1.Columns.Add(col1);
}
private void FailedMessageBox_Load(object sender, EventArgs e)
{
dataGridView1.DataSource = Global.ASMs;
}
}
I want to make sure that when the user clicks OK the current ASMs in the list get set to ERROR which is why I thought a bindinglist would work the best
I am wondering if there was a quick way to do this or if I just have to do a bunch of loops.
What about something similar in your Page_load:
using(var context = new DbContext())
{
// You could put a Where Clause here to limit the returns
// i.e. context.ASMs.Where(s => s.Status == ASMStatus.IDLE).Load()
context.ASMs.Load();
var data = context.ASMs.Local.ToBindingList();
var bs = new BindingSource();
bs.DataSource = data;
dataGridView1.DataSource = bs;
}
You should add a BindingSource directly to the page but I am just showing adding it in code. Then you can access it like this:
foreach(DataRow row in dataGridView1.Rows)
{
if ((bool) row.Cells["Device Failed"].Value == true)
{
var line = row.DataBoundItem();
line.Status = ASMStatus.ERROR;
}
}
Make sure you save the changes.
This is the section of the form I am working on:
The following code links the BindingNavigator to the dataset using a bindingSource. Can I use this binding source to hook up the two text boxes to the data?
Do I simply need to use a property of the textboxes or is this more involved?
i.e when the form loads the first record's fields "Work Phrase" and "Description" will be displayed and when I scroll using the navigator the values in these boxes will change accordingly.
public partial class uxRevisionHelperForm : Form
{
public SqlCeConnection conn = new SqlCeConnection(ConfigurationManager.ConnectionStrings["WindFormAppRevisionHelper.Properties.Settings.DefinitionsDBConnectionString"].ConnectionString);
BindingSource definitionsBindingSource = new BindingSource();
public uxRevisionHelperForm()
{
InitializeComponent();
uxDescriptionTextBox.AutoSize = true;
this.hookUpBindingNavigator();
}
public void hookUpBindingNavigator()
{
SqlCeDataAdapter da = new SqlCeDataAdapter(new SqlCeCommand("Select * From tb_Definitions",conn));
DataSet ds = new DataSet("Helper");
ds.Tables.Add("DefinitionsTable");
da.Fill(ds.Tables["DefinitionsTable"]);
// Assign the BindingSource.
this.uxBindingNavigator.BindingSource = this.definitionsBindingSource;
this.definitionsBindingSource.DataSource = ds.Tables["DefinitionsTable"];
}
Try using the DataBinding collection of the textboxes.
Something like this:
uxDescriptionTextBox.DataBindings.Add("Text",
definitionsBindingSource,
fieldInTable);
Have added the full source code (highlighting exactly your requirement) here - http://sdrv.ms/NyXHdu. Download > Open the solution in VS2010 > Hit F5
[Update]
Double click on Form.cs designer and observe the productListBindingSource. It bound to a custom object - The ProductList class
Then see the properties of the TextBoxes & ComboBox and observe the DataBindings > Text property. They are bound to the productListBindingSource's individual item. See Image below.
Courtsey - http://www.apress.com/9781590594391/ [Chapter 8]
Goal:
Once clicking on add or delete button, the datagridview should be refreshed with the latest data from document.
Problem:
The datagridview can't be refreshed
after making changes by deleting or
adding new data.
I'm using binding source that is linked with datagridview's datasource.
I tried everything with different solution and read advise from different forum but still I can't solve this problem.
I also tried using these syntax "BindingSource.ResetBindings(false)", "BindingSource.Refresh()" etc but no result.
Links below:
How to refresh a bindingsource
http://www.eggheadcafe.com/community/aspnet/2/10114324/datagridview-refresh-from-another-form.aspx
http://blogs.msdn.com/b/dchandnani/archive/2005/03/15/396387.aspx
http://bytes.com/topic/c-sharp/answers/812061-problem-refresh-datagridview
bSrcStock.DataSource = myProductrepository.GetAllProductList();
dgridStock.DataSource = null;
dgridStock.DataSource = bSrcStock;
bSrcStock.ResetBindings(true);
dgridStock.Columns[0].Width = 101;
dgridStock.Columns[1].Width = 65;
dgridStock.Columns[2].Width = 80;
dgridStock.Columns[3].Width = 120;
dgridStock.Columns[4].Width = 90;
I have faced this same issue and found out that the problem is with the initialization of the BindingSource inside a static constructor (The class was a singleton). Upon realizing this, I moved the code to the calling event and it finally worked without needing to assign null or call the clear method. Hope this helps.
No need to define the columns (unless you really want to...)
Then just call for the refreshDataGridView Method every time you add or remove something from your list...
public List<CustomItem> ciList = new List<CustomItem>();
CustomItem tempItem = new CustomItem();
tempItem.Name = "Test Name";
ciList.add(tempItem);
refreshDataGridView();
private void refreshDataGridView()
{
dataGridView1.DataSource = typeof(List<>);
dataGridView1.DataSource = ciList;
dataGridView1.AutoResizeColumns();
dataGridView1.Refresh();
}
You need a list that will inform the BindingSource when an item is added etc. Use a System.ComponentModel.BindingList for that.
Dim lisItems As New System.ComponentModel.BindingList(Of myObject)
Works Great! Only AddRange is missing so this takes care of that:
Private Sub AddRange(ByVal lis As List(Of myObject))
For Each itm In lis
lisItems.Add(itm)
Next
End Sub
https://learn.microsoft.com/en-us/dotnet/api/system.componentmodel.bindinglist-1?view=netframework-4.7.2