The issue I am having right now is saving data of my applications when I exit. I am using the MVVM pattern to create this application. The application is a simple DataGrid which is bound to a list of Users which are of type TestModel that has a Name, Last Name, Department and an ID.
public ObservableCollection<TestModel> Users { get; set; } = new ObservableCollection<TestModel>();
public MainWindowViewModel()
{
Users.Add(
new TestModel { ID = 1, NAME = "George", LastName = "Williams"});
Users.Add(
new TestModel { ID = 2, NAME = "Bob", LastName = "Smith"});
}
<DataGrid x:Name="MainDataGrid" Grid.Row="0" Grid.Column="1" ItemsSource="{Binding Users}" SelectedItem="{Binding SelectedItem}" AutoGenerateColumns="False" IsReadOnly="True">
<DataGrid.InputBindings>
I implemented another view to add a new User to the list as well as a 3rd view to edit the details about the selected user. Everything works fine.
The issue now is that when I exit my application, all of the Users I created during the session are gone, the data is not saved permanently, only those Users which I created in the MainWindowViewModel constructor remain on launch. How can I save the data permanently so the Users I add during a session are there when I launch again? I am not using a database.
Related
I am sorry I am asking question on stack over flow first time so might be some thing i done wrong.
I have started learning WPF MVVM and I'm stuck.
I have one parameter master table in a database, and it has the columns parameterid, parametername, parametertype. It is populated with master data, e.g., country master has parametertype "country", city has "city" parametertype, but parameterid will be unique.
Now I have a customer page, where in the customerviewmodel object I have countryId and CityId parameters to be saved inside the customer object.
How can I bind this parameterId directly with customer.CountryId from XAML? Or is that not possible?
Currently I have achieved it as follows: defined one CountrySelectedItem Property and bound it with combobox SelectedItem. When its property changes, when anyone changes its value then in viewmodel I set the Customer's CountryId in CountrySelectedItem set property.
How do I validate the Customer's countryID property? In the combo box, I have bound the Parameter Master's object so can't write data Annotation's Required attribute to the Parameter Master Entity.
Here are the complete Scenario
public class Customer
{
public int CustomerId { get; set; }
[Required]
public string CustomerName { get; set; }
[Required]
public int CountryId { get; set; }
}
<telerik:RadComboBox x:Name="cmCountryId" Grid.Row="3" Grid.Column="1" HorizontalAlignment="Left"
ItemsSource="{Binding LstCountry}"
HorizontalContentAlignment="Left" VerticalAlignment="Center"
DisplayMemberPath="ParameterName"
SelectedItem="{Binding SelectedCountry,Mode=TwoWay}" Height="25" Width="200" >
</telerik:RadComboBox>
/* To Fill DropDown Country DropDown From ParameterMaster*/
public List<ParameterEntity> LstCountry { get; set; }
LstContainerType = new List<ParameterEntity>(parameterService.GetParamterTypeDetail("COUNTRY").ToList());
/*
Parameter Master has ParameterId,ParameterName,ParameterType -- All Master Data Stored Inside It with Different ParameterType.
*/
/* When User Select CountrId then I Set It's ParameterID As CountryID In My CustomerEntity */
public ParameterEntity SelectedCountry
{
get
{
return _selectedCountry;
}
set
{
_selectedCountry = value;
RaisePropertyChanged("SelectedCountry");
SelectedCustomerEntity.CountryId = _selectedCountry != null ? _selectedCountry.ParameterId : 0;
}
}
So Here Is my question for above Scneraio.
1) To Bind Customer Object's CountryId Property From CountryDropDown is that any other option available then this one.
SelectedCustomerEntity.CountryId = _selectedCountry != null ? _selectedCountry.ParameterId : 0;
// please have a look SelectedCountry property.
Something like , I do not need to write Selected Property and i Can Directly Set ParameterId To CountryId Of CustomerEntity From XAML
Or this one is right scneario.
2) Another Question Is How To do Validation On CountryId ComboBox.
i mean As Mention in CustomerEntity has Required CountryId But In XAMl Design of SelectedItem="{Binding SelectedCountry,Mode=TwoWay}"
What should i write to display if user has not select any country from dropdown. Should I write a logic on Save Button manully ?
I'll start by making an assumption that your creating a form that will have a submit button on it that will save the selected data in some manor.
For the combobox, you can use the SelectedValuePath to select a field from the type you are binding as your selections.
<ComboBox SelectedValue="{Binding SelectedCountry}"
ItemsSource="{Binding Countries}"
SelectedValuePath="ParameterId" />
Then your SelectedCountry property in your view model will be set to the ParameterId.
For the second question of validation as well as how to bind to the Customer.CountryIdin your submit function on your model you would first check if SelectedCountry is null or empty then error out showing the validation error message. Otherwise set the Customer.CountryId = SelectedCountry and save the customer.
I'll get this out of the way right off the bat... my base view model class is implementing INotifyPropertyChanged. Here's the scenario:
I have a single view with a single view model. The view is a master/detail with the master being a list box of Game objects that I'm populating without issue. When a Game object is selected in the master list box, I want to populate some details in various controls. The control that's causing me problems is a combo box.
Now, the combobox is being populated using a collection of Team objects. Each Game object has a "Team" object and once the combobox is populated, I want to select the appropriate Team object in the combobox that the Game object specifies.
Now, I know this is working to some degree because if I do the same binding to a textbox, the right information appears (I can get the bound Team object to appear in the textbox, but I can't get it to select from the list).
I'm seriously lost, been working on this for a few hours now. Can anyone assist?
Edit: I have a feeling this has something to do with the object references. But wouldn't SelectedValue still work?
ViewModel:
public ObservableCollection<Team> Teams
{
get { return this.teams; }
set
{
this.teams = value;
OnPorpertyChanged("Teams");
}
}
public Team SelectedTeam
{
get { return this.selectedTeam; }
set
{
this.selectedTeam = value;
OnPorpertyChanged("SelectedTeam");
}
}
private ObservableCollection<Team> teams;
private Team selectedTeam;
Team Class:
public class Team
{
public string Name { get; set; }
}
View:
<ComboBox DisplayMemberPath="Name"
ItemsSource="{Binding Teams}"
SelectedItem="{Binding Mode=OneWayToSource, Path=SelectedTeam}" />
I'm doing some rapid prototyping and is trying to mock out an admin interface for a website and went with WCF RIA Services. I'm able to expose and consume the domain services from server to client, but I'm struggling with getting columns autogenerated in the datagrid when the result of the query on the server holds no data.
<riaControls:DomainDataSource Name="domainDataSource1"
LoadSize="20" QueryName="GetUsers" AutoLoad="True" >
<riaControls:DomainDataSource.DomainContext>
<ds:CobraDomainContext />
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<sdk:DataGrid ItemsSource="{Binding Data, ElementName=domainDataSource1}" AutoGenerateColumns="True" IsReadOnly="False" Width="250" Height="150" >
</sdk:DataGrid>
This renders an empty 250x150 datagrid (no columns/no rows). I was expecting that the colunms for the user entity were displayed even though no data was returned from the server since the view would kind of suck otherwise initially. My brain can't can't seem to figure out what is wrong, so I'll crowdsource with stackoverflow.
UPDATE: I was kind of expecting the result from the query to be a typed enumeration, but it appears that the result of the query on the DomainDataService is just IEnumerable but not typed, so the internal logic needs to look into the list to discover what kind of data it is containing.
So the updated question is: Can I give the DataGrid a hint on what type of data will be returned or otherwise autogenerate columns in the grid (through XAML or code)??
I guess your ItemsSource enumeration is not typed, right? If it's just a list of objects, the datagrid will not find the entity public properties.
I don't know how your entity class is, but try this code to see what I'm talking about:
Somewhere:
public class User {
public string Name { get; set; }
public int Age { get; set; }
}
Xaml:
<my:DataGrid x:Name="datagrid"/>
Codebehind:
public MainPage() {
InitializeComponent();
datagrid.ItemsSource = new List<User>();
}
The list is empty but datagrid will pick the column names since I'm using a List of Users. It could be an Enumeration of Users, etc..
I hope it helps,
Cheers
EDITED: about the updated question: You could try using a Converter.
EDIT: The issue underneath is fixed, GO TO EDIT2 in this post.
I have an Organisation entity and a Region entity. An object of type Organisation can have one or more Region objects connected to it, thus I have a foreign key in my Region entity to the Organisation Entity. The Organisation and Region objects are pulled from my database using WCF RIA and entity framework. I want to put the Organisation objects in one ComboBox and the Region objects in another ComboBox, and when selecting an organsation having the ComboBox for Region objects automatically only showing regions that are connected to the selected organisation. Should be pretty basic, but the way I've designed it right now it doesnt work at all.
So, any hint to how I can achive this? A simple simple codeexample is much appreciated!
(I'm using SL4,WCF RIA MVVM)
EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2 EDIT2:
Using Venomo's ElemntBinding answer this is working great for me now when I want to add a new object to my collection, and I'm just pulling the avaible countries and connected regions and then type a site in a textbox...So I get my combination of Organisation, region and site in my database :)
Now, I've got a new problem when I want to EDIT a site in my collection. In EDIT mode, I want the two dropdowns to be preselected and disabled (BusinessRule is that I can edit the sitename, not which organisation og region it's connected to). So by setting the SelectedIndex property on Organisation combobox I get my organisation selected, but when doing the same on the Regions combobox it fails with an Object Reference error.
You can achieve this with some clever ElementBindings.
Basic example:
Let's say we have a simple class like this:
public class Country
{
public string Name { get; set; }
public IEnumerable<string> Regions { get; set; }
}
Then, we'll have two ComboBoxes: one for choosing a country and another for choosing a region in that country. The second one should update itself when the value of the first one changes.
Okay, first we have to tell Silverlight how to display a Country. For complex scenarios we could use a DataTemplate for that, but for now, we will only need the DisplayMemberPath property of the ComboBox class.
<ComboBox x:Name="cbCountries" DisplayMemberPath="Name"/>
So, we create a simple collection of these objects in the code behind:
var countries = new List<Country>()
{
new Country
{
Name = "USA",
Regions = new List<string>
{
"Texas", "New York", "Florida", ...
},
},
new Country
{
Name = "UK",
Regions = new List<string>
{
"Scotland", "Wales", "England", ...
},
},
...
};
I know that those are not all of the regions in the example countries, but this is a Silverlight example and not a geographical lesson.
Now, we have to set the ItemsSource of the ComboBox to this collection.
cbCountries.ItemsSource = countries;
Both of these can be in the constructor in the code-behind.
Okay, now back to XAML!
We'll need another ComboBox and a way for telling it to get its items from the other collection dynamically.
Binding its ItemsSource to the other ComboBox's selected item is just the most obvious way to achieve that.
<ComboBox x:Name="cbRegion" ItemsSource="{Binding ElementName=cbCountries, Path=SelectedItem.Regions}"/>
This should do the trick quite simply.
If you use MVVM:
You can bind to the ItemsSource of the first ComboBox from the ViewModel. The rest remains the same.
To tell what the selected values are to the ViewModel, use Two-way bindings on the SelectedItem property of both ComboBoxes and bind that to whatever property you have for it in the ViewModel.
If your collection can change dynamically:
If the list of the countries (or whatever it is that you want to use this for) can change during runtime, it is best if you implement INotifyPropertyChanged for the Country class and for the regions, use ObservableCollection<>.
If it doesn't need to change during runtime, no need to bother with these.
View Model:
public ObservableCollection<Organisation> Organisations { get; set; }
private Organisation selectedOrganisation;
public Organisation SelectedOrganisation
{
get { return this.selectedOrganisation; }
set
{
if (this.selectedOrganisation != value)
{
this.selectedOrganisation = value;
this.NotifyPropertyChanged("SelectedOrganisation");
this.UpdateRegions();
}
}
private IEnumerable<Region> regions;
public IEnumerable<Region> Regions
{
get { return this.regions; }
set
{
if (this.regions != value)
{
this.regions = value;
this.NotifyPropertyChanged("Regions");
}
}
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private void UpdateRegions()
{
// If regions are not pre-populated you might need to perform a new call to
// the service that retrieves organisations in order to retrieve the associated Regions entities
// for the SelectedOrganisation organisation
this.Regions = this.SelectedOrganisation.Regions;
}
In your View:
<ComboBox x:Name="Organisations" ItemsSource="{Binding Organisations}" SelectedItem="{Binding SelectedOrganisation, Mode=TwoWay}" />
<ComboBox x:Name="Regions" ItemsSource="{Binding Regions}" />
I have 3 data tables:
User
UserID, UserName
1, Bat
2, John
etc...
Member
MemberID, Member
1, Local
2, Zone
etc...
UserMember
UserID,MemberID
1, 1
1, 2
2, 1
etc...
On the user input XAML Form in WPF
Check list box is bound to the Member table.
My Question:
I want it so that when the user checks the member type, the selected values automatically gets inserted into the UserMember table. And when the the user unchecks member type, the selected values are deleted from the UserMember table.
How can I do this in WPF?
It depends on what kind of software methodology you want to use (I like MVVM with WPF) what kind of ORM(Linq, EF, Castle, etc.).
your could create a ViewModel like so:
public class UserViewModel
{
int UserId {get;set;}
Collection<Member> MemberList {get;set;}
}
public class Member
{
bool _IsMember;
bool IsMember
{get return _IsMember;set _IsMember = value; EditMemberStatus();}
int MemberId {get;set;}
string Member {get;set;}
void EditMemberStatus()
{
if (IsMember)
//Code to add row into db using your ORM choice
else
//Code to remove row from db
}
}
in your xaml you could do this:
<ListView ItemsSource={Binding MemberList}>
<ListView.View>
<GridView>
<GridViewColumn Header="IsMember"}>
<CheckBox IsChecked="{Binding IsMember}"/>
</GridViewColumn
<GridViewColumn Header=Member DisplayMemberBinding={Binding Member}/>
</GridView>
</ListView.View>
</ListView>
And finally in the code behind of your xaml you have this
public class UserView
{
UserView()
{
InitializeComponent();
DataContext= new UserViewModel();
}
}
This is just a skeleton, hope this helps. It's also only one way of a myriad of ways to do it.