简体   繁体   中英

Passing Data from a Data class to a View

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM