I have 2 windows Parent window - Window_Products and Child window - Window_NewProduct
1)In my Window_Products
I have a list ObservableCollection ProductsList in this window which displays a list of products
AddNewProduct() is used to add new product to the list from child window
public AddNewProduct()
{
Window_NewProduct newProduct = new Window_NewProduct();
if(newProduct.ShowDialog() = true)
{
ProductsList.Add(//what code should I write here);
}
}
2)In my Window_NewProduct
This window uses a user control ProductUserControl since I use the user control as a Page as well as Window
<Window>
<local:ProductUserControl x:Name="ProductUserControl">
</Window>
3)In my product user control
public ProductUserControl()
{
this.DataContext = new ProductViewModel();
}
4)In my ProductViewModel
I have this object Product that stores the values like Prod_Name,Prod_Code in it.
What I want is this object Product to be returned to the parent window(Window_Products) after I save the product into database so that I can add new product to the observable collection above.
How can my object return back from the view model through the usercontrol,child window and then reach parent window.
Help me around this. Thanks in advance.
Make a new constructor for the indow_NewProduct:
public ProductUserControl(ProductViewModel model):base()
{
this.DataContext = model;
}
In your example :
1)In my Window_Products becomes:
var myPVM = new ProductViewModel();
Window_NewProduct newProduct = new Window_NewProduct(myPVM);
if(newProduct.ShowDialog() = true)
{
ProductsList.Add(myPVM.<THE NEW PRODUCT PROPERTY YOU WILL WRITE>);
}
A couple of things:
1. This is not good, but it may fit your needs:
2. Take a look at MVVM and MVC, combine them to also have controlers.
3. In WPF you should try as much as possible to use the DataContext to move your data arround, this NewProduct could be part of the prant's window data context.
Add a dependency property for your user control and bind to that in the xaml as below.
public static readonly DependencyProperty ProductProperty = DependencyProperty.Register(
"Product", typeof(ProductDto), typeof(ProductUserControl), new FrameworkPropertyMetadata(null));
public ProductDto Product
{
get { return (ProductDto)this.GetValue(ProductProperty); }
set { this.SetValue(ProductProperty, value); }
}
<TextBox Margin="2" Text="{Binding Path=Product.Code, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Margin="2" Text="{Binding Path=Product.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
You should have a Product property for your Window_NewProduct's view model
public class Window_NewProductViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private ProductDto product;
public ProductDto Product
{
get
{
return this.product;
}
set
{
if (value != this.product)
{
this.product = value;
NotifyPropertyChanged();
}
}
}
}
Then in the Window_NewProduct xaml you should bind this property to the usercontrols dependency property
<local:ProductUserControl x:Name="ProductUserControl" Product="{Binding Product}"/>
Add parameter to the Window_NewProduct constructor that takes in the ProductDto and passes that to the ViewModel.
public Window_NewProduct(ProductDto product)
{
InitializeComponent();
this.DataContext = new Window_NewProductViewModel() { Product = product };
}
Then in your MainWindow you can just create a new productDto to pass on to the DetailsWindow.
var newProduct = new ProductDto();
var window_NewProduct = new Window_NewProduct(newProduct);
if (window_NewProduct.ShowDialog() == true)
{
Debug.WriteLine(newProduct.Code);
Debug.WriteLine(newProduct.Name);
}
Related
I have a XDocument read from xml file:
public ObservableCollection<Product> GetProducts()
{
ObservableCollection<Product> _products = new ObservableCollection<Product>();
XDocument doc = XDocument.Load(#".\Config\MCU.xml");
foreach (XElement productRow in doc.Root.Elements("MCU"))
{
var m = new Product(productRow.Element("MCUName").Value, Convert.ToUInt32(productRow.Element("MCUNumber").Value), Convert.ToUInt32(productRow.Element("FlashAddress").Value),
Convert.ToUInt32(productRow.Element("PageCount").Value), Convert.ToUInt32(productRow.Element("PageSize").Value), productRow.Element("BinFile").Value,
Convert.ToUInt32(productRow.Element("RAMCodeAdd").Value), Convert.ToUInt32(productRow.Element("MainCR").Value), Convert.ToUInt32(productRow.Element("CRTrimmingAdd").Value),
Convert.ToUInt32(productRow.Element("CRTrimmingLength").Value), Convert.ToUInt32(productRow.Element("UIDAdd").Value), Convert.ToByte(productRow.Element("UIDLength").Value),
productRow.Element("UID").Value, productRow.Element("UserArea").Value);
_products.Add(m);
}
return _products;
}
Now I want to binding XElement MCUName to combobox:
<ComboBox x:Name="cb_MCUType" SelectedItem="{Binding MCUName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
ItemsSouce in the code behind:
public MainWindow()
{
InitializeComponent();
cb_MCUType.ItemsSource = App.ProductDb.GetProducts();
}
But this doesn't work, the combobox populate the Product, how should I fix this? Thanks!
Update:
Thanks for the replies. As you suggested, now I would like to write this in MVVM, so I change my original code:
XAML:
<ComboBox x:Name="cb_MCUType" ItemsSource="{Binding ProductsList}" SelectedValue="{Binding SelectedProduct}" DisplayMemberPath="MCUName" />
ViewModel:
public class MainViewModel : INotifyPropertyChanged
{
private ProductDB pd = new ProductDB();
public MainViewModel()
{
DefaultValue_Load();
}
public ObservableCollection<Product> ProductsList { get; set; }
private Product _selectedProduct;
public Product SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
NotifyPropertyChanged("SelectedProduct");
}
}
public void DefaultValue_Load()
{
ProductsList = new ObservableCollectioin<Product>(pd.GetProducts());
}
}
When you create the Products in GetProducts() you provide MCUName as the first parameter in the constructor. For the following sample, I'll assume, that there is a property McuName on every product:
public MainWindow()
{
InitializeComponent();
cb_MCUType.ItemsSource = App.ProductDb.GetProducts().Select(p => p.McuName);
}
It is worth to mention, that this is not a clean MVVM implementation. You should consider to redesign your application to follow the MVVM patter.
I'm trying to set binding on a TapGestureRecognizer in code and I can't figure out the right way to do it. The working xaml looks something like this...
<Grid>
<Grid.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LaunchLocationDetailsCommand}"
CommandParameter="{Binding}" />
</Grid.GestureRecognizers>
</Grid>
And in C#, it looks something like this...
var gridTap = new TapGestureRecognizer();
gridTap.SetBinding(TapGestureRecognizer.CommandProperty,
new Binding("LaunchLocationDetailsCommand"));
gridTap.SetBinding(TapGestureRecognizer.CommandParameterProperty,
new Binding(/* here's where I'm confused */));
var grid = new Grid();
grid.GestureRecognizers.Add(gridTap);
My confusion comes in on the binding of CommandParameterProperty. In xaml, this simply {Binding} with no other parameter. How is this done in code? Passing in new Binding() or this.BindingContext don't seem to work.
The CommandProperty binding is the same as you was doing.
As you are not passing in a path to some property to use, your CommandParameterProperty can't just create an empty Binding as it will throw an exception.
To get around this you need to specify the Source property as Adam has pointed out.
Note, however if the BindingContext you are trying to assign is Null, which I suspect it is in your case, this will still throw an exception.
The Grid in the example below has the BindingContext set to the view model (objGrid.BindingContext = objMyView2).
We are then creating a new binding for our command parameter, with the Source pointing back to our view model (Source = objGrid.BindingContext).
If you run the demo below, you will see a debug message in the Output window indicating a property value from the view model.
MyView2 objMyView2 = new MyView2();
objMyView2.SomeProperty1 = "value1";
objMyView2.SomeProperty2 = "value2";
objMyView2.LaunchLocationDetailsCommand_WithParameters = new Command<object>((o2)=>
{
LaunchingCommands.LaunchLocationDetailsCommand_WithParameters(o2);
});
Grid objGrid = new Grid();
objGrid.BindingContext = objMyView2;
objGrid.HeightRequest = 200;
objGrid.BackgroundColor = Color.Red;
TapGestureRecognizer objTapGestureRecognizer = new TapGestureRecognizer();
objTapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, new Binding("LaunchLocationDetailsCommand_WithParameters"));
Binding objBinding1 = new Binding()
{
Source = objGrid.BindingContext
};
objTapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandParameterProperty, objBinding1);
//
objGrid.GestureRecognizers.Add(objTapGestureRecognizer);
Supporting classes:-
MyView2:-
public class MyView2
: ViewModelBase
{
public string SomeProperty1 { get; set; }
public string SomeProperty2 { get; set; }
public ICommand LaunchLocationDetailsCommand_WithParameters { get; set; }
}
LaunchingCommands:-
public static class LaunchingCommands
{
public static void LaunchLocationDetailsCommand_WithParameters(object pobjObject)
{
System.Diagnostics.Debug.WriteLine("SomeProperty1 = " + (pobjObject as MyView2).SomeProperty1);
}
}
ViewModelBase:-
public abstract class ViewModelBase
: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string pstrPropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(pstrPropertyName));
}
}
}
If you have a {Binding} with nothing inside it, it is binding to the binding context and passing that through. Hence you bind it to the default binding context of the page.
When you create a new Binding set the source.
var binding = new Xamarin.Forms.Binding() { Source = this.BindingContext };
i have three usercontrol in a C# win application ; the main User is called UcReferenteTecnico that only contains UcContatto that has a nested usercontrol UcIndirizzo.
UcContatto has a modelView named ContattoMV and UcIndirizzo has a modelview named IndirizzoMV
UcContatto modelview has a properies and a nested IndirizzoMV properties; they are done in this way:
public class ContattoMV:INotifyPropertyChanged
{
string _NOME_CONTATTO;
[HeaderAttribute("Nome contatto", true, 2)]
public string NOME_CONTATTO
{
get { return _NOME_CONTATTO; }
set
{
_NOME_CONTATTO = value;
NotifyPropertyChanged("NOME_CONTATTO");
}
}
public IndirizzoMV Indirizzo
{
get { return _Indirizzo; }
set
{
_Indirizzo = value;
NotifyPropertyChanged("Indirizzo");
}
}
public void NotifyPropertyChanged(string aiPropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(aiPropertyName));
}
}
}
public class IndirizzoMV:INotifyPropertyChanged
{
public string TOPONIMO
{
get { return _TOPONIMO; }
set
{
_TOPONIMO = value;
NotifyPropertyChanged("TOPONIMO");
}
}
public void NotifyPropertyChanged(string aiPropertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(aiPropertyName));
}
}
}
All properties are binding in UcContatto and in UcIndirizzo to Control in this way:
In UcContatto:
this.txtNome.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this._bsContatto, "NOME_CONTATTO", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
and to bind nested usercontrol UcIndirizzo do this:
this.ucIndirizzo1.DataBindings.Add(new System.Windows.Forms.Binding("BsIndirizzo", this._bsContatto, "Indirizzo", true));
where _bsContatto is typeof ContattoMV and BsIndirizzo is bindable properties done in this way:
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IndirizzoMV BsIndirizzo
{
get
{
return (IndirizzoMV)_bsIndirizzo.DataSource;
}
set
{
if (value == null)
{
return;
}
_bsIndirizzo.DataSource = value;
}
}
In UcIndirizzo properites is binding in this way:
this.txtToponimo.DataBindings.Add(new System.Windows.Forms.Binding("EditValue", this._bsIndirizzo, "TOPONIMO", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
where _bsIndirizzo is typeof IndirizzoMV.
In UcContatto to spread properties to main UserControl i use another bindable properties in this way:
[Bindable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public ContattoMV BsContatto
{
get
{
return (ContattoMV)_bsContatto.DataSource;
}
set
{
if (value == null)
{
return;
}
_bsContatto.DataSource = value;
}
}
to initialize usercontrol in main Control UcReferenteTecnico i do this:
this.ucContatto1.BsContatto = new ContattoMV();
when i change value in my usercontrol if i set value in txtNome , NOME_CONTATTO properties is valued (enter in breakpoint put in set properties)
if i change value in ucIndirizzo in txtToponimo no properties is valued
where is my error?
thanks a lot
I'd say that your error is not using XAML to define your Bindings, but I guess that you might have some valid reason for that. I found it really difficult to follow your question because of all of the foreign type and property names, so while I don't think that I can help directly with your problem, I can provide this simple advice:
When you want to data bind to a property that is in a parent view model, you can simply use a RelativeSource Binding:
Imagine that this was in the parent view model:
public string NOME_CONTATTO
{
get { return _NOME_CONTATTO; }
set
{
_NOME_CONTATTO = value;
NotifyPropertyChanged("NOME_CONTATTO");
}
}
You could data bind to it directly from any child view like this:
<TextBox Text="{Binding DataContext.NOME_CONTATTO,
RelativeSource={RelativeSource AncestorType={x:Type Local:ParentView}}}" ... />
Alternatively, if you just want to pass some value between view models, you can use delegates... see my answer to the How to call functions in a main view model from other view models? question to find out how to do that.
I am trying to use the following code example from the Infragistics site and I'd like edits in the XamDataCards to be reflected in the XamDataGrid. However, my DataSource for the XamDataGrid is an ObservableCollection<Companies> in my ViewModel. How can I also bind to the card and relay updates back to my Companies object in the ViewModel?
<igDP:XamDataGrid x:Name="dgCompanies" Theme="IGTheme" DataSource="{Binding Companies}" SelectedDataItemsScope="RecordsOnly">
<igDP:XamDataGrid.FieldSettings>
<igDP:FieldSettings CellClickAction="SelectCell" AllowEdit="True"/>
</igDP:XamDataGrid.FieldSettings>
</igDP:XamDataGrid>
<igDP:XamDataCards x:Name="XamDataCards1"
Grid.Row="1"
DataSource="{Binding Path=SelectedDataItems, ElementName=dgCompanies}"
Theme="IGTheme">
Edit: Added ViewModel
public class CompanyMgmtViewModel : ViewModelBase
{
private ObservableCollection<Object> _Companies = null;
public ObservableCollection<Object> Companies
{
get { return _Companies; }
set
{
if (_Companies != value)
{
_Companies = value;
RaisePropertyChanged(GetPropertyName(() => Companies));
}
}
}
public CompanyMgmtViewModel()
{
this.LoadData();
}
public void LoadData()
{
ObservableCollection<Object> records = new ObservableCollection<Object>();
var results = from res in AODB.Context.TCompanies
select res;
foreach (var item in results)
if (item != null) records.Add(item);
Companies = records;
}
}
The Model/Context code is just EF Database First generated.
You would need to bind your XamDataGrid's SelectedDataItems property to a property of type object[] ie. SelectedCompanies in your ViewModel and bind to that for your XamDataCards' datasource.
The accepted answer in this thread has a sample that shows how to do this, albeit with a ListBox instead of XamDataCards:
http://www.infragistics.com/community/forums/t/89122.aspx
Just replace that ListBox with your XamDataCards control, it works and updates the XamDataGrid. The ViewModel in the example is contained in the MainWindow code-behind, so it is MVVM like you want.
more info:
http://help.infragistics.com/Help/Doc/WPF/2014.1/CLR4.0/html/xamDataGrid_Selected_Data_Items.html
IG's SelectedDataItems is an object[] :
http://help.infragistics.com/Help/Doc/WPF/2014.1/CLR4.0/html/InfragisticsWPF4.DataPresenter.v14.1~Infragistics.Windows.DataPresenter.DataPresenterBase~SelectedDataItems.html
I couldn't have gotten to this answer without Theodosius' and Ganesh's input - so thanks to them, they both had partial answers.
I first tried to bind the SelectedDataItems of the XamDataGrid to the XamDataCards by way of a property on the ViewModel as Theodosius suggested, but that wasn't enough. Thanks to Ganesh, I implemented INotifyPropertyChanged on my model objects, by inheriting from ObservableObject in MVVMLight (how did I not know the Model needed this?).
Below are the relevant pieces of code to make it work.
I also implemented PropertyChanged.Fody as documented here; that's where the TypedViewModelBase<T> and removal of RaisePropertyChanged() comes from.
I'm also creating my Model objects by using a LINQ/Automapper .Project().To<T>() call which can be found here.
Model
public class Company : ObservableObject
{
public Company() { }
public int id { get; set; }
public string strName { get; set; }
public string strDomicileCode { get; set; }
}
ViewModel
public class CompanyMgmtViewModel : TypedViewModelBase<Company>
{
private ObservableCollection<Object> _Companies = null;
private Object[] _selectedCompany = null;
public Object[] Company
{
get { return _selectedCompany; }
set
{
if (_Company != value)
{
_selectedCompany = value;
}
}
}
public ObservableCollection<Object> Companies
{
get { return _Companies; }
set
{
if (_Companies != value)
{
_Companies = value;
}
}
}
public CompanyMgmtViewModel()
{
this.LoadData();
}
public void LoadData()
{
ObservableCollection<Object> records = new ObservableCollection<Object>();
var results = AODB.Context.TCompanies.Project().To<Company>();
foreach (var item in results)
if (item != null) records.Add(item);
Companies = records;
}
}
View
<igDP:XamDataGrid x:Name="dgCompanies"
Theme="IGTheme"
DataSource="{Binding Companies, Mode=OneWay}"
SelectedDataItemsScope="RecordsOnly"
SelectedDataItems="{Binding Company}">
...
<igDP:XamDataCards x:Name="XamDataCards1"
Grid.Row="1"
DataSource="{Binding ElementName=dgCompanies, Path=SelectedDataItems}"
Theme="IGTheme">
If I have a observablecollection in a page that inserts items on a listview. How can I add to that same observablecollection(listview) from a different window(class)? I do not want to use INotifyPropertyChanged and all that. All I'm trying to do is add a item to the existing listview. I have tried literally everything and I can't figure it out. Please any help is appreciated.
CampersPage...(BindingCamper is just my way of basically saying new ObservableCollection()
public partial class CampersPage : Page
{
MainWindow _parentForm;
public GridViewColumnHeader currentColumnSorted = null;
private SortAdorner currentAdorner = null;
String request1;
String request2;
String request3;
String request4;
// public ObservableCollection<Camper> Campers { get; private set; }
public CampersPage(MainWindow parent)
{
_parentForm = parent;
InitializeComponent();
_parentForm.bindings = new BindingCamper();
for (int i = 0; i < _parentForm.allCampers.Count; i++)
{
if (_parentForm.allCampers[i].getRequest(1) != null && _parentForm.allCampers[i].getRequest(2) != null && _parentForm.allCampers[i].getRequest(3) != null && _parentForm.allCampers[i].getRequest(4) != null)
{
request1 = _parentForm.allCampers[i].getRequest(1).getName();
request2 = _parentForm.allCampers[i].getRequest(2).getName();
request3 = _parentForm.allCampers[i].getRequest(3).getName();
request4 = _parentForm.allCampers[i].getRequest(4).getName();
}
_parentForm.bindings.Campers.Add(new Camper { FirstName = "" + _parentForm.allCampers[i].getFirstName(), LastName = "" + _parentForm.allCampers[i].getLastName(), Ages = _parentForm.allCampers[i].getAge(), SchoolGrade = _parentForm.allCampers[i].getGrade(), Gender = "" + _parentForm.allCampers[i].getGender(), bindingRequest1 = request1, bindingRequest2 = request2, bindingRequest3 = request3, bindingRequest4 = request4 });
//DataContext = _parentForm.bindings;
}
DataContext = _parentForm.bindings;
}
---Now I click on a button and a new window comes up where I would like to add a new camper to the listview in CampersPage.
public partial class AddNewCamper : Window
{
MainWindow _parentForm;
public AddNewCamper(MainWindow parentForm)
{
InitializeComponent();
_parentForm = parentForm;
// _parentForm.bindings = new BindingCamper();
}private void btnSubmitNewCamper_Click(object sender, RoutedEventArgs e)
{
String firstName = txtNewFirstName.Text;
String lastName = txtLastName.Text;
int age;
int grade;
String newage = comboNewAge.Text;
if (firstName != "" && lastName != "" && IsNumber(txtNewGrade.Text) && newage != "")
{
age = Convert.ToInt16(newage);
grade = Convert.ToInt16(txtNewGrade.Text);
// Create New Camper
Camper person = new Camper(age, grade, boxNewGender.Text, firstName, lastName);
_parentForm.allCampers.Add(person);
//This is just adding the camper to the listview. Not sure if it is actually adding it to the database.
_parentForm.bindings.Campers.Add(new Camper { FirstName = person.getFirstName(), LastName = person.getLastName(), Ages = person.getAge(), SchoolGrade = person.getGrade() });
//CampersPage p = new CampersPage(_parentForm);
DataContext = _parentForm.bindings;
Do I have to somehow add AddNewCamper's namespace to CampersPage's namespace in xaml?
<ListView HorizontalAlignment="Stretch" Margin="0,12" x:Name ="listViewCampers" ItemsSource="{Binding Campers}" DisplayMemberPath="bindMe" IsSynchronizedWithCurrentItem="True" Grid.Column="1">
ObservableCollection class:
public partial class BindingCamper
{ // This class assist in binding campers from listview to the textboxes on the camperspage
public ObservableCollection<Camper> Campers { get; set; }
public ObservableCollection<Staff> StaffMembers { get; set; }
public ObservableCollection<Schedule> schedule { get; set; }
public ObservableCollection<Group> Groups { get; set; }
public BindingCamper()
{
Campers = new ObservableCollection<Camper>();
StaffMembers = new ObservableCollection<Staff>();
schedule = new ObservableCollection<Schedule>();
Groups = new ObservableCollection<Group>();
}
I won't go as far as claiming you're using WPF wrong, but you're certainly making your life difficult. I suggest reading up a bit on MVVM pattern - it really makes WPF development easier (here's good starting article).
Approach you're using at the moment is not correct on several levels:
your windows/pages need to have way too much knowledge about each other to work properly
result of which, is dependency on parent form in your child windows (while what you really need is dependency on window context, which in fact is campers list)
you need to do too much manual notifications/setting up to achieve your goals (while WPF has great tools to do it automatically)
you seem to be exposing model (allCampers) through view (MainWindow)
All of this can be solved with a bit of redesigning:
Your views (Main, CampersPage, AddNewCamper) should be dependent on BindingCamper class (which essentially could be view model for them), not on each other
Same instance of BindingCamper should be set as DataContext for all of them
You should not add bindings manually (like you're doing now); all can (and should) be done from XAML
Having above in mind, your CampersPage class should look like this:
public partial class CampersPage : Page
{
public CampersPage(BindingCamper camper)
{
InitializeComponent();
DataContext = camper;
}
}
It should by no means initialize data for parent window and set it's binding. This is simply wrong.
Actually, this approach (providing data context through constructor) can be used in all your view classes (AddNewCamper and MainWindow too, probably).
Now, when you need campers page, say from your main window, it gets very easy:
public partial class MainWindow : Window
{
public void ShowCampers()
{
var campersPage = new CampersPage((BindingCampers) this.DataContext);
// show campersPage
}
}
It is the same with AddNewCamper window. Just pass it data context. When you add new camper, add it to BindingCamper.Campers list (which is available through data context):
// rest of the btnSubmitNewCamper_Click method elided
Camper person = new Camper(age, grade, boxNewGender.Text, firstName, lastName);
((BindingCamper)this.DataContext).Campers.Add(person);
That's all. Thanks to combined mechanisms of data binding and observable collection, this new element will immediately be visible both in MainWindow and CampersPage.
Edit:
Code to fetch campers from database should be wrapper with some kind of DAO object (as a part of DAL - I know, lot of ugly buzzwords, but luckily they are all related and fairly obvious). For example, you can have a class that will deal with getting campers from database:
public class CampersProvider
{
public IEnumerable<Camper> GetAllCampers()
{
// here you put all your code for DB interaction
// and simply return campers
}
}
To give you quick solution, you can once again pass CampersProvider to MainWindow constructor, call GetAllCampters method and build observable collection for BindingCamper. However, this is not very MVVM approach. Those stuff usually is handled by view model (yet another, separate class), which at the moment you don't have.
Code you posted requires quite some work, I think it won't be a bad idea if you read a bit about MVVM pattern and try to apply it to your application.