Повторное использование обязательных коллекций для WPF - PullRequest
4 голосов
/ 08 августа 2011

Я работаю над приложением WPF, используя шаблон MVVM, который я изучаю . Он использует EF4. Я пытаюсь использовать аналогичный стиль интерфейса документа с вкладками; несколько полей со списком на этих вкладках имеют одинаковые источники элементов (из базы данных sql). Поскольку эти данные почти никогда не меняются, было бы неплохо создать объект хранилища, чтобы получить их при запуске приложения, и просто повторно использовать их для каждой модели представления. По какой-то причине, хотя я использую new в конструкторах, списки связаны.

Если я установлю связанное комбинированное окно на одной вкладке, оно будет установлено на другой вкладке (или настроено при создании новой вкладки). Я не хочу, чтобы это случилось, но я не знаю, почему.

Объект репозитория инициализируется раньше всего на свете и содержит только публичные списки. Представления просто используют привязку источника элементов к ObservableCollection. Я использую класс ViewModelBase из статьи. Вот модель и модель модели.

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");
        }
    }

Модель

public ObservableCollection<Customer> CustomerList { get; set; }

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

РЕДАКТИРОВАТЬ: Я уверен, что это неправильный способ сделать это, я все еще работаю над этим. Вот новый код модели:

        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());
    }

Это вызывает новую проблему. Всякий раз, когда вы меняете вкладки, выбор в поле со списком очищается.

БОЛЬШЕ РЕДАКТИРОВАНИЯ: Этот вопрос Я столкнулся с вопросом, когда ответ Rachels указывает на то, что статический репозиторий является плохой практикой, поскольку он оставляет соединение с БД открытым на весь срок действия программы. Я подтвердил, что соединение остается открытым, но похоже, что оно остается открытым и для нестатических классов. Вот код репозитория:

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 = "" });

Однако теперь я возвращаюсь к уродливому коду выше, который не кажется хорошим решением для копирования коллекции, поскольку объект Customer должен быть вручную воссоздан по свойству свойства в любом коде, который нуждается в этом. Похоже, что это должно быть очень распространенным делом, повторное использование списков, я чувствую, что оно должно иметь решение.

1 Ответ

4 голосов
/ 08 августа 2011

Пользовательские объекты, такие как Customer, передаются по ссылке, а не по значению. Поэтому, даже если вы создаете новый ObservableCollection, он по-прежнему заполнен объектами Customer, которые существуют в вашем хранилище. Чтобы создать действительно новую коллекцию, вам нужно создать новую копию каждого Customer объекта для вашей коллекции.

Если вы создаете несколько копий CustomerList, поскольку хотите фильтровать коллекцию в зависимости от ваших потребностей, вы можете использовать CollectionViewSource вместо ObservableCollection. Это позволяет вам возвращать отфильтрованное представление коллекции вместо самой полной коллекции.

EDIT

Если нет, рассматривали ли вы возможность использовать статический список для элементов ComboBox и просто сохранить SelectedItem в вашей модели?

Например,

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

Это заполнило бы ComboBox свойством ObservableCollection<Customer> CustomerList, которое находится в Статическом классе Lists, и связало бы SelectedItem со свойством Model.Customer

Если SelectedItem напрямую не ссылается на элемент в ComboBox ItemsSource, вам нужно перезаписать Equals() класса элемента, чтобы сделать два значения равными, если их значения одинаковы. В противном случае он сравнивает хеш-код двух объектов и решает, что эти два объекта не равны, даже если содержащиеся в них данные совпадают. В качестве альтернативы вы можете также связать свойства SelectedValue и SelectedValuePath в ComboBox вместо SelectedItem.

...