Проблема привязки данных пользовательского элемента управления со списком и MVVM - PullRequest
1 голос
/ 04 октября 2011

Я создал пользовательский элемент управления WPF с 2 ListBox es (с именами «Источник» и «Значение») и кнопкой «Добавить», которые позволяют пользователю «копировать» элементы, связанные с источником * 1002. * к значению ListBox. Вот код:

public partial class MultiListSelect : UserControl
{
    public static readonly DependencyProperty ListSourceProperty;
    public static readonly DependencyProperty ListValueProperty;

    public IEnumerable ListSource  
    {
        get { return (ObservableCollection<object>)GetValue(MultiListSelect.ListSourceProperty); } 
        set { SetValue(MultiListSelect.ListSourceProperty, value); }  
    }

    public IEnumerable ListValue
    {
        get { return (ObservableCollection<object>)GetValue(MultiListSelect.ListValueProperty); }
        set { SetValue(MultiListSelect.ListValueProperty, value); }
    }  


    public MultiListSelect()
    {
        InitializeComponent();
    }

    static MultiListSelect()  
     { 

         MultiListSelect.ListSourceProperty =  
            DependencyProperty.Register("ListSource",
            typeof(IEnumerable), typeof(MultiListSelect));

         MultiListSelect.ListValueProperty =
            DependencyProperty.Register("ListValue",
            typeof(IEnumerable), typeof(MultiListSelect));

     }

    private void btnAdd_Click(object sender, RoutedEventArgs e)
    {
        foreach (object o in listBoxSource.SelectedItems)
        {
             listBoxValue.Items.Add(o);
        }
    }

}

Мое представление, которое использует этот пользовательский элемент управления, использует MVVM Light. Вот мой код ViewModel, который предоставляет данные, привязанные к каждому ListBox:

public class ProfileViewModel : ViewModelBase
{
    public User User { get; set; }

    // This gets bound to the Source listbox
    private ObservableCollection<OperatingArea> _operatingAreas;
    public ObservableCollection<OperatingArea> OperatingAreas 
    { 
        get { return _operatingAreas; }
        private set
        {
            _operatingAreas = value;
        }
    }

    public ProfileViewModel()
    {
        OperatingAreas = _rpDomain.LoadOperatingAreas();
        WindowsIdentity identity = WindowsIdentity.GetCurrent();

        if (User == null)
        {
            User = _rpDomain.CreateUser();
            User.Preferences = _rpDomain.CreateUserPreferences();
            User.UserId = identity.Name;

            _rpDomain.Add(User);
        }

        if (User.Preferences == null)
        {
            User.Preferences = _rpDomain.CreateUserPreferences();
        }

        if (User.Preferences.ViewableOperatingAreas == null)
        {
            // This gets bound to my 'Value' ListBox
            User.Preferences.ViewableOperatingAreas = new ObservableCollection<OperatingArea>();
        }
    }
}

Переплет работает нормально. Проблема заключается в том, что когда пользователь выбирает элементы в поле со списком «Источник» и нажимает кнопку «Добавить», я получаю сообщение об ошибке, когда эта строка выполняется в коде позади пользовательского элемента управления в обработчике события btnAdd_Click:

listBoxValue.Items.Add(o);

Я получаю сообщение об ошибке: «Операция недействительна, когда используется ItemSource. Получайте доступ и изменяйте элементы с помощью ItemsControl.ItemsSource вместо '. Итак, я понимаю проблему, но я не знаю лучший способ решить эту проблему. DependencyProperties имеют тип IEnumerable, поэтому я не могу добавить их непосредственно в код за пользовательским элементом управления. Также я не могу получить доступ к ViewModel и напрямую обновить свойства, потому что библиотека пользовательского элемента управления не может ссылаться на ViewModel для Views. Каков наилучший способ скопировать элементы из поля со списком «Источник» в поле со списком «Значение» (предпочтительнее иметь код, содержащийся в пользовательском элементе управления, а не требовать, чтобы View / ViewModel добавлял элементы). Кроме того, это пользовательский элемент управления, поэтому тип, который привязывается к каждому списку, зависит от использования элемента управления.

РЕДАКТИРОВАТЬ - 10-4-2011

Итак, реальный вопрос в том, как мне обновить (добавить) список «Значение» из моего пользовательского элемента управления? Свойство зависимости имеет тип IEnumerable, поэтому его нельзя обновить напрямую, и, как показано выше с ошибкой, я не могу просто вызвать listbox.items.Add (). Я использую MVVM, поэтому обязательным является привязка данных к свойствам, предоставляемым во ViewModel. Также пользовательский элемент управления не знает (и не должен знать) тип, связанный с ним во время выполнения. Я понимаю, что мой пользовательский элемент управления может вызвать событие «Добавлено», которое может быть обработано с помощью функции EventToCommand в MVVM Light, но это кажется ненужным - лично я не буду удовлетворен, если куплю элемент управления у стороннего поставщика элементов управления, который потребовал от меня обновить коллекцию сам. Я знаю, что это возможно, потому что это, по сути, способ, которым работает комбинированный список - этот комбинированный список имеет как свойство ItemsSource, так и свойство SelectedValue, которое можно связать со свойствами ViewModel.

<ComboBox 
    ItemsSource="{Binding Path=Categories}"
    DisplayMemberPath="Name"
    SelectedValue="{Binding Path=SelectedCategory, Mode=TwoWay}"/> 

1 Ответ

0 голосов
/ 04 октября 2011

Items и ItemsSource являются взаимоисключающими, если для ItemsSource задано значение, Items.Add(..) сгенерирует. Не используйте ItemsSource, даже если это самый простой вариант, используйте Items.Add в цикле (вы можете вызвать его из обработчика событий изменения значения DP).

Пожалуйста, дайте мне знать, если вам нужна дополнительная помощь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...