I'm studying MVVM and doing creating an app for practice
I was trying to make an app where you can add and view student's everything was ok until I tried to separate the Observable Collection from the rest of the ViewModel and be able to use it the other ViewModels.
My question is how to use an ObservableCollection or any other kind of data holder that is outside of any ViewModel in every View?
Tell me if you need code?
Here is the class with the data in the solution explorer the path to the file is Data/Database
public class StudentDatabase
{
#region Defining and Populating an ObservableCollection
// Defining an observable collection to hold the students
private ObservableCollection<Student> studentData;
// Populating the ObservableCollection
public StudentDatabase()
{
studentData = new ObservableCollection<Student>()
{
new Student(){Name="John", Surname="Smith", Age=17},
new Student(){Name="Barbara", Surname="Johnson", Age=16}
};
}
// Defining and setting the field for the Observable collection
public ObservableCollection<Student> StudentData
{
get { return studentData; }
set { RaisePropertyChanged("studentData"); }
}
#endregion
#region RaisePropertyChange implementation
/// <summary>
/// INotifyPropertyChanged implementation:
/// A property notifies something that it has changed
/// and the other object get's the new data
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
Here is the XAML of the page where I want to show it
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="15*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ListBox DataContext="{Binding Path=Data.StudentDatabase}"
ItemsSource="{Binding StudentData}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Name"
Grid.Column="0"
Text="{Binding Name}"/>
<TextBlock x:Name="Surname"
Grid.Column="1"
Text="{Binding Surname}"/>
<TextBlock x:Name="Age"
Grid.Column="2"
Text="{Binding Age}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
And search window c sharp code
public partial class Search: Window
{
public Search()
{
InitializeComponent();
}
}
I have this error in the output window in visual studio
System.Windows.Data Error: 40 : BindingExpression path error: 'Data' property not found on 'object' ''StudentDatabase' (HashCode=2650314)'. BindingExpression:Path=Data.StudentDatabase; DataItem='StudentDatabase' (HashCode=2650314); target element is 'ListBox' (Name=''); target property is 'DataContext' (type 'Object')
I want the update of the list box to be dynamic so I do not include an Update button
EDIT: I've updated the code but I think I'm not doing something right again, could someone light me the way?
EDIT: If I set the DataContext in the codebehind everything is ok but if I try to set the DataContext onlt for the specific control in XAML then I don't get the list does not display the data
here is a link to Skydrive where I uploaded the project
if the codebehind is this everything works
InitializeComponent();
DataContext = new Data.StudentDatabase();
but if I don't use the codebehind and do it in XAML like this nothing happens
DataContext="{Binding Path=Data.StudentDatabase}"
I am obviously missing something here
It is an application design issue. If you want share a collection with all the views, you need to put it inside the application view model, something like the MainViewModel
. Also you need to be albe to access it from all the views, for doing this you may have a reference the MainViewModel
in every view's view models that you want to show the collection. Another way is share the MainViewModel
instance, you may save it in the application resources. If you use Galasoft MVVMLight Toolkit
you may access the MainViewModel
throught the ViewModelLocator
. Hope this ideas helps...
EDIT After adding your code, I can note that you are not understanding very well the ViewModel
pattern. Your class StudentObservableCollection
should be the StudentViewModel
, and it should only have the student properties. Also you need to have a class for to manage the StudentViewModel
s. In this class you should have the StudentsData
or an ObservableCollection<StudentViewModel>
, in this class also you may have other properties like SelectedStudent
of type StudentViewModel
. Like I said in my original answer, if the collection of students should be aviable on several views in the app, you may create it in a global view model.
George,
If you are looking to share something like a database throughout your app, you can create the resource in your MainWindow and any controls defined under the visual tree of MainWindow will have access to that resource.
So in MainWindow XAML, do:
<Window.Resources>
<local:StudentDatabase x:Key="StudentDatabase"/>
<Window>Resources>
and in any controls after that, you can do something like <ListBox DataContext="{StaticResource StudentDatabase}"/>
and that will use your StudentDatabase.
I would suggest making your Database static though, because every time you use {StaticResource StudentDatabase}
it will try to reinitialize that class. Making it static you will be able to create one instance and use it throughout your application.
When you want to modify your database, in code-behind you can call something like StudentDatabase sDB = (DataContext as StudentDatabase);
in an event, and you will be able to call your functions for modifying the db.
Consider this:
<Window x:Class="Project.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Project"
Title="Search" Height="300" Width="300">
<Window.Resources>
<local:StudentDatabase x:Key="StudentDatabase"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<ListBox x:Name="StudentItemListBox"
Grid.Row="5" Grid.ColumnSpan="3"
DataContext="{StaticResource StudentDatabase}"
ItemsSource="{Binding StudentData}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Surname}"
Grid.Column="1"/>
<TextBlock Text="{Binding Age}"
Grid.Column="2"/>
<!--Here go some other info about the students-->
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel>
<Button x:Name="Exit"
<!--TO-DO: Write an exit command-->/>
</StackPanel>
</Grid>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.