Reusing Bindings for WPF

I am working on a WPF application using the MVVM pattern that I am learning . He uses EF4. I am trying to use a similar tabbed interface style; several combined fields on these tabs have the same element sources (from sql db). Since this data almost never changes, it would seem like a good idea to create a repository object in order to get it when the application starts, and just reuse it for each view model. However, although I use new in the constructors, the lists are linked.

If I set the linked list box on one tab, it is set to another (or set when creating a new tab). I do not want this to happen, but I do not know why.

The repository object is initialized before anything else and contains only public lists. Views simply use the binding of the source of the objects to the ObservableCollection. I am using the ViewModelBase class from the article. Here is the Viewmodel model and model.

ViewModel

TicketModel _ticket; public TicketViewModel(TableRepository repository) { _ticket = new TicketModel(repository); } public ObservableCollection<Customer> CustomerList { get { return _ticket.CustomerList; } set { if (value == _ticket.CustomerList) return; _ticket.CustomerList = value; //base.OnPropertyChanged("CustomerList"); } } 

Model

 public ObservableCollection<Customer> CustomerList { get; set; } public TicketModel(TableRepository repository) { CustomerList = new ObservableCollection<Customer>(repository.Customers); } 

EDIT: I'm sure this is the wrong way to do this, I'm still working on it. Here is the new model code:

  public TicketModel(TableRepository repository) { CustomerList = new ObservableCollection<Customer>((from x in repository.Customers select new Customer { CM_CUSTOMER_ID = x.CM_CUSTOMER_ID, CM_FULL_NAME = x.CM_FULL_NAME, CM_COMPANY_ID = x.CM_COMPANY_ID }).ToList()); } 

This causes a new problem. Whenever you change tabs, the selection in the combo box is cleared.

MORE EDITING: This question I came across that using the Rachels answer indicates that a static repository is bad practice as it leaves the database connection open for the program to live. I confirmed that the connection remains open, but it looks like it remains open for non-static classes as well. Here is the repository code:

 using (BT8_Entity db = new BT8_Entity()) { _companies = (from x in db.Companies where x.CO_INACTIVE == 0 select x).ToList(); _customers = (from x in db.Customers where x.CM_INACTIVE == 0 orderby x.CM_FULL_NAME select x).ToList(); _locations = (from x in db.Locations where x.LC_INACTIVE == 0 select x).ToList(); _departments = (from x in db.Departments where x.DP_INACTIVE == 0 select x).ToList(); _users = (from x in db.Users where x.US_INACTIVE == 0 select x).ToList(); } _companies.Add(new Company { CO_COMPANY_ID = 0, CO_COMPANY_NAME = "" }); _companies.OrderBy(x => x.CO_COMPANY_NAME); _departments.Add(new Department { DP_DEPARTMENT_ID = 0, DP_DEPARTMENT_NAME = "" }); _locations.Add(new Location { LC_LOCATION_ID = 0, LC_LOCATION_NAME = "" }); 

However, now I will return to the ugly code, which does not seem to be a good solution for copying the collection, since the Customer object must be manually restored by the property of the property in any code that it needs. It seems like this should be very common, reusing lists, I feel like it should have a solution.

+4
source share
1 answer

Custom objects, such as Customer , are passed by reference, not by value. Therefore, even if you create a new ObservableCollection , it is still populated with Customer objects that exist in your repository. To create a truly new collection, you will need to create a new copy of each Customer object for your collection.

If you create multiple copies of CustomerList because you want to filter the collection according to your needs, you can use CollectionViewSource instead of ObservableCollection. This allows you to return the filtered view of the collection, rather than the complete collection.

EDIT

If not, have you considered using a static list for your ComboBox components and just saved SelectedItem in your model?

For instance,

 <ComboBox ItemsSource="{Binding Source={x:Static local:Lists.CustomerList}}" SelectedItem="{Binding Customer}" /> 

This would populate the ComboBox with the ObservableCollection<Customer> CustomerList property, which is in the Static Lists class, and bind the SelectedItem to the Model.Customer property

If the SelectedItem does not refer directly to the item in the ComboBox ItemsSource , you need to overwrite the Equals() of the item class so that both values ​​are the same if their values ​​are the same. Otherwise, it will compare the hash code of the two objects and decide that the two objects are not equal, even if the data they contain is the same. Alternatively, you can also bind the SelectedValue and SelectedValuePath properties to a ComboBox instead of SelectedItem .

+4
source

All Articles