I have a combo box populated using dataset table adapters. I have a textbox and a button next to it. Onclick of this button the textbox value is added to the database. I want to refresh my Combobox once any new entry has been made. I did my research and figured out that I will have to Create an ObservableCollection and fill it with the data from DB. But since I am using dataset all the classes for each of the table is already present.
Here is my code:
XAML
<ComboBox Name="service" SelectedValuePath="Id" DisplayMemberPath="Service" ></ComboBox>
<TextBox Name="txtTobeAdded"></TextBox>
<Button Name="add" Content="Add" Click="add_Click"></Button>
C#
public partial class Window3 : Window
{
private SqlDatatsetTableAdapters.ServicesTableAdapter tableAdapterServices = new SqlDatatsetTableAdapters.ServicesTableAdapter();
public Window3()
{
InitializeComponent();
System.Data.DataView vw = tableAdapterServices.GetData().DefaultView;
service.ItemsSource = vw;
service.SelectedIndex = 0;
}
private void add_Click(object sender, RoutedEventArgs e)
{
tableAdapterServices.InsertQuery(txtTobeAdded.Text);
}
}
your scenario : Whatever changes to the database must be reflected to the combobox..
solution 1 : just call the another form as ShowDialog() instead of Show() and as soon as the child form is closed bind the datasource of the combobox again. as u can query the database again and retrieve the data again.
solution 2 : Just have a static List and send the newly added value to the Parent form from the child form using the Parent constructor.
try:
private void add_Click(object sender, RoutedEventArgs e)
{
tableAdapterServices.InsertQuery(txtTobeAdded.Text);
service.ItemsSource = tableAdapterServices.GetData().DefaultView;;
service.SelectedIndex = 0;
}
Its a lazy solution pushing the values back into the combo box. If you would like to learn the way to do it using an observable collection you will have to look at data Binding and the MVVM design pattern. More Info Found here
Related
How can I add rows to a data grid view using a separate form? When I'm trying to pass it like this
private void btnDodajPrzychod_Click(object sender, EventArgs e)
{
formMain.gridPrzychody.Rows.Add("123");
this.Close();
}
it says that an object reference is required for the non-static field method or property "formMain.gridPrzychody".
How can I fix it? Thanks
When you calling the new Form, you must pass a handler to access the gridView from previous form. the handler could be the first form object or the gridview object.
for example:
FormNew fm = new FormNew(this.gridPrzychody);
then in the new form get and store the handler. when ever you want, you can use it then.
GridView gridView;
public FormNew(GridView gridView)
{
this.gridView = gridView;
}
I am trying to do something simple here. I just want to pass selected items from a listview as a list to another window so I can bind it to combobox. Below is the code for my button that generates the list.
public void Button_Click(object sender, RoutedEventArgs e)
{
Attendees = new List<Person>();
foreach (Person attendee in lvUsers.SelectedItems)
{
Attendees.Add(attendee);
}
this.Close();
}
How do I pass this list to another window and bind it please?
snap Attendees list as filed in your window like
private List<Attendee> Attendees;
then on button click assign it and when you displaying new window of other form pass to constructor like
From1 myForm = new Form1(Attendees);
This was easy enough to do I just didn't have experience at the time. what I should have done is declared a public list and referenced it from another page. Or create a user control where I can change the datacontext so it can be binded.
I have a form (Form1) which contains a grid, bound to a DataSource via a BindingSource.
I then have a button, which once clicked opens another form (Form2) that should let a user enter new data.
I pass the BindingSource from Form1 to Form2, and the goal is that once the user "saves" his input in Form2, it'll be automatically added to Form1.
Is there a way to do this, w/o directly accessing the UI controls?
I.E -
public partial class Form2 : Form
{
BindingSource bs = new BindingSource();
public Form2(BindingSource bindingSourceFromForm1)
{
InitializeComponent();
this.bs = bindingSourceFromForm1;
}
private void button1_Click(object sender, EventArgs e)
{
DataRow dr = (this.bs.DataSource as DataTable).NewRow();
dr["Col1"] = this.textBox1.Text;
dr["Col2"] = this.textBox2.Text;
this.bs.Add(dr);
}
}
Is there a way to bind the controls on Form2 (in the example above textBox1/2) to the BindingSource, and then have it automatically add the values in textBox1 & 2?
Something like calling this.bs.Add(), where Add() knows where to take it's values without me explicitly telling it to go to the textboxes, since it's bound to the aforementioned controls?
Thanks!
If you add a BindingSource to the form designer as you would normally do, set the DataSource to the same source so you can bind the textboxes.
In the specialized constructor the following code adds a new record to the DataSource of form1, assigns the DataSource to the DataSource of the BindingeSource instance of this form and sets the position. Your new Form will enable the user the enter the values in that new object.
public Form2(BindingSource bindingSourceFromForm1)
: this()
{
bindingSourceFromForm1.AddNew();
this.bindingSource1.DataSource = bindingSourceFromForm1.DataSource;
this.bindingSource1.Position = bindingSourceFromForm1.Position;
}
If your user can cancel the operation you have to compensate for that by calling RemoveCurrent on the bindingSourceFromForm1 but I leave that as excersice as it is not clear if you want/need that.
I have a classic Form with 3 textboxes and 1 combobox. Combobox shows list of Users and 3 textboxes should contain details about the selected user in the combobox. For selected user I have a special attribute (as shown below) which I am using as data source. This is ok only on the first run. When the form is shown, changing user in combobox has no effect.
public partial class UserAdministration : Form
{
private readonly DataManager _dataManager = DataManager.Instance;
private User _selectedUser;
public UserAdministration()
{
InitializeComponent();
}
private void UserAdministration_Load(object sender, EventArgs e)
{
AddUsers();
textBoxName.DataBindings.Add("Text", _selectedUser, "Name");
textBoxSurname.DataBindings.Add("Text", _selectedUser, "Surname");
textBoxPassword.DataBindings.Add("Text", _selectedUser, "Password");
}
private void AddUsers()
{
var users = _dataManager.UserProvider.GetAll().Select(pair => pair.Value).ToList();
comboBoxUsers.DataSource = new BindingSource { DataSource = users };
comboBoxUsers.DisplayMember = "ListViewText";
if (users.Count > 0)
comboBoxUsers.SelectedIndex = 0;
}
private void comboBoxUsers_SelectedIndexChanged(object sender, EventArgs e)
{
_selectedUser = comboBoxUsers.SelectedItem as User;
}
}
What am I missing? What is wrong with data binding?
to bind your datasource to cb use this code:
comboBoxUsers.DataSource = users (directly to you datasource);
to bind the same data to textbox do it like this:
textbox1.DataBindings.Add("Text", users, "username", true);
the only point is, that you need to link both controls to the same ds instance
I have a form with ONLY a textbox that I wanted to bind to database column.
When I used the 'properties' settings to data-bind that textbox to one column, it created the bindingSource1 and table adapter for me.
When I clicked the SAVE button, I simply added bindingSource1.EndEdit(); and then it saved correctly to the database.
I have the following DataGrid
<DataGrid CanUserDeleteRows="True"
CanUserAddRows="True"
SelectedItem="{Binding SelectedResource, Mode=TwoWay}"
ItemsSource="{Binding Path=Resources, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
IsAsync=True}"> ... </<DataGrid>
I am using the MVVM pattern to bind to an ObservableCollection<ResourceViewModel> Resources and this works great. I have a button that adds a new row and this is done by adding a new ResourceViewModel to the Resources collection - great. Now, I want the user to be able to click on the empty last row, and this automatically creates a new record in the DataGrid.
I have made sure the DataGrid has CanUserAddRows=True. I have made sure the class in the collection Resources (ResourceViewModel) that I am binding to has a default constructor (no parameters) and I have made sure the collection type is not readonly. When the user clicks on the last row the default constructor fires but to correctly instantiate the new ResourceViewModel object in need a reference to either the grid of the Resources collection...
I suppose I could use and AttachedCommand on the CellBeginEdit event and then add a new ResourceViewModel to the observable collection there, is there a standard way of doing this?
Note, I have read the following questions and these are of no help to me
WPF DataGrid - Event for New Rows?
How to add rows with a DataGrid and MVVM
Edit. It turns out that I am having problems doing this due to a bug in the WPF DataGrid. See Nigel Spencer's Blog. However, his fix is not working for me at the moment...
As far as I understand, you know how to correctly add new items into your data bound collection to result in a new item being added to the DataGrid and your question actually relates to how can you do this when the user clicks on the last row in the DataGrid. The general way to handle some event in the view model is to create an Attached Property (if one does not already exist) that handles that event for you.
For instance, you could create an Attached Property that attaches a handler to the relevant event and another of type ICommand which you could execute when the event handler is called. Then you could write the functionality of that ICommand in your view model (in which you add a new item to your data bound collection) and data bind your ICommand implementation to the Attached ICommand Property.
As I'm fairly sure you know how to define Attached Propertys, I won't insult you by showing you. Please let me know if I have misunderstood you, or not made myself clear.
Here's an attached property that registers a command for adding rows (assuming the source collection contains a generic type argument):
public static readonly DependencyProperty RegisterAddCommandProperty = DependencyProperty.RegisterAttached("RegisterAddCommand", typeof(bool), typeof(DataGridExtensions), new PropertyMetadata(false, OnRegisterAddCommandChanged));
public static bool GetRegisterAddCommand(DependencyObject obj)
{
return (bool)obj.GetValue(RegisterAddCommandProperty);
}
public static void SetRegisterAddCommand(DependencyObject obj, bool value)
{
obj.SetValue(RegisterAddCommandProperty, value);
}
static void OnRegisterAddCommandChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (sender is DataGrid)
{
var DataGrid = sender as DataGrid;
if ((bool)e.NewValue)
DataGrid.CommandBindings.Add(new CommandBinding(AddCommand, AddCommand_Executed, AddCommand_CanExecute));
}
}
public static readonly RoutedUICommand AddCommand = new RoutedUICommand("AddCommand", "AddCommand", typeof(DataGridExtensions));
static void AddCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
var DataGrid = sender as DataGrid;
var ItemsSourceType = DataGrid.ItemsSource.GetType();
var ItemType = ItemsSourceType.GetGenericArguments().Single();
DataGrid.Items.Add(Activator.CreateInstance(ItemType));
}
static void AddCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = (sender as DataGrid).CanUserAddRows;
}
And then you can apply the command to a button somewhere like this:
<Button Command="{x:Static Extensions:DataGridExtensions.AddCommand}"/>
Don't forget to specify the command target.