Свойство выбранного элемента не реагирует на привязку

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

<TextBox x:Name="Texty" 
  Text="{Binding CurrentThing.Texty}" ... />

<ComboBox x:Name="Picky"
  ItemsSource="{x:Static local:MainWindow.AllPickables}"
  SelectedItem="{Binding CurrentThing.Picked}" ... />

Кажется, что привязка действует, потому что текстовое поле получает правильное содержимое. Поле со списком также правильно отображает значения в списке. Однако проблема в том, что выбор не производится.

Сначала я подумал, что это связано с тем, что некоторые контроллеры имеют другое значение по умолчанию для Mode, поэтому я попытался явно установить его как двусторонний для поля со списком. Насколько я мог видеть, никакой разницы в поведении.

Что я делаю не так. Как ее решить (или хотя бы устранить неисправность)?

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

Я пробовал добавить DisplayMemberPath, как было предложено. Это не сработало и элементы поля со списком больше не присутствуют. Я предполагаю, что DisplayMemberPath относится к тому, где взять материал для разбивки на элементы из всего, что упоминается в ItemSource (и там нет Picked) .

<ComboBox x:Name="Picky"
  ItemsSource="{x:Static local:MainWindow.AllPickables}"
  SelectedItem="{Binding CurrentOrder}"
  DisplayMemberPath="Picked" ... />

Полный (почти) исходный код для сенарио

Просмотр назначения модели в главном окне.

<Window.DataContext>
  <local:Presenter/>
</Window.DataContext>

Используемая модель представления (уменьшенная версия относительно рассматриваемых компонентов, чтобы быть минимальным примером).

public class Presenter : INotifyPropertyChanged
{
  private ObservableCollection<Thing> _allThings;

  private Thing _currentThing;
  public Thing CurrentThing
  {
    get { return _currentThing; }
    set { _currentThing = value; OnPropertyChanged(); }
  }

  public ListCollectionView AllThingsView { get; set; }

  private IEnumerable<PickType> _allPickables;
  public IEnumerable<PickType> AllPickables
  {
    get { return _allPickables; }
    set { _allPickables = value; OnPropertyChanged(); }
  }

  public Presenter()
  {
    _allThings = new ObservableCollection<Thing>(DataAccessor.GetThings());
    AllThingsView = new ListCollectionView(_allThings);
    _allPickables = DataAccessor.GetPickables();
  }

  public event PropertyChangedEventHandler PropertyChanged;

  [NotifyPropertyChangedInvocator]
  protected virtual void OnPropertyChanged([CallerMemberName] String name = null)
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
  }
}

Код главного окна позади (части, которые относятся к используемым элементам управления и событиям). У меня также есть представление сетки под названием ThingListing в моей разметке, которое привязано к AllThingsView в моей модели представления. Когда я нажимаю на запись в ней, запускаемое событие должно обновить значение CurrentThing и изменить вкладку на ту, где размещены связанные элементы управления. Кажется, что все попадает в нужные места, принимает выбранные элементы для полей со списком. У меня также есть удобный метод расширения Get. Он делает то, что вы интуитивно думаете (проверено с течением времени).

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
    DataContext = new Presenter();
  }

  private void ThingListing_OnMouseDoubleClick(Object sender, MouseButtonEventArgs eventArgs)
  {
    DataContext.Get<Presenter>().CurrentThing
      = sender.Get<DataGrid>().CurrentItem.Get<Thing>();

    Dispatcher.BeginInvoke((Action)(() => tabControl.SelectedIndex = 1));
  }
}

person Konrad Viltersten    schedule 22.01.2015    source источник
comment
Однако проблема в том, что выбор не производится. Хм, что? Не могли бы вы добавить информацию о том, чего вы хотите достичь? Установить выбранный элемент ComboBox, написав текст в TextBox? Или что?   -  person Herdo    schedule 22.01.2015
comment
@Konrad Покажите, как определены AllPickables и CurrentThing.   -  person Clemens    schedule 22.01.2015
comment
Попробуйте поместить фиктивный преобразователь в выражение привязки и увидеть переданные туда значения.   -  person Amit Raz    schedule 22.01.2015
comment
Почему SelectedItem привязан к свойству CurrentThing (Picked)? Похоже, эта привязка должна быть {Binding CurrentThing}.   -  person Derrick Moeller    schedule 22.01.2015
comment
У меня тоже была эта проблема. Если возможно, попробуйте следующее: ‹ComboBox ... DataContext = {Binding CurrentThing} SelectedItem = {Binding Picked} ... /›   -  person Herman Cordes    schedule 22.01.2015
comment
Я согласен с FrumRoll, похоже, что SelectedItem должен быть привязан к CurrentThing. Чтобы отобразить свойство Current Thing в поле со списком, вам, вероятно, следует использовать DisplayMemberPath. т.е. DisplayMemberPath = Выбрано   -  person Theodosius Von Richthofen    schedule 22.01.2015
comment
настройте Visual Studio на отображение окна вывода и изучение того, что в нем написано, обычно ошибки привязки дадут вам хорошую подсказку. я предполагаю, что он будет жаловаться, потому что вы пытаетесь привязать к свойству вещи, когда вам нужно просто привязать к самой вещи, и нужно определить displaymemberpath, чтобы указать поле со списком, какое свойство отображать в нем   -  person Theodosius Von Richthofen    schedule 22.01.2015
comment
Ни в коем случае: FrumRoll прав!   -  person Il Vic    schedule 22.01.2015
comment
@HermanCordes Вы используете DataContext вместо ItemSource. Это то, что рекомендуется для элемента управления combobox? Я не достаточно сообразителен, чтобы решить, но кажется, что intellisense дает мне CurrentThing при вводе после ItemSource, но нет при вводе после DataContext . Пожалуйста, имейте в виду, что, несмотря на все мои попытки, я мог недостаточно хорошо объяснить установку. DataContext содержит свойство с именем CurrentThing. Это не сам CurrentThing.   -  person Konrad Viltersten    schedule 22.01.2015
comment
@FrumRoll Моя модель представления имеет несколько свойств, одно из которых - CurrentThing (текущая вещь фактически является одним из элементов в свойстве AllThings, которое отображается в сетке данных. I хотел отслеживать объект, который составляет определенную строку в сетке данных. Итак, в модели представления у меня есть информация о текущем элементе. В этом элементе есть свойство, которое определяет, что следует выбрать в поле со списком. Извините, если я не понял. Я подумал, что это не имеет значения, и я попытался привести минимальный пример внимания к читателям. Никто не любит читать неактуальные гигабайты.   -  person Konrad Viltersten    schedule 22.01.2015
comment
@TheodosiusVonRichthofen Пожалуйста, посмотрите мою правку в вопросе. Я пробовал это и думаю, что могу узнать, почему ваше предложение не сработало. Однако вполне возможно, что вы что-то поняли. Как мне перейти к выбранному элементу, а не к источнику элемента с помощью пути к отображаемому элементу?   -  person Konrad Viltersten    schedule 22.01.2015
comment
SelectedItem необходимо привязать к тому же типу объекта, что и ItemsSource. ItemsSource - это коллекция типа Pickable, свойство SelectedItem должно иметь тип Pickable. Тогда DisplayMemberPath покажет свойство Pickable. Я предполагаю, что TimeFrame - это свойство типа Pickable   -  person Theodosius Von Richthofen    schedule 22.01.2015
comment
@TheodosiusVonRichthofen Первый - опечатка. Не знаю, как он туда попал ... Тоже - поехали! Я подавал слишком ограниченный набор информации. Прости. Нет - время комплектации не совпадает с текущим заказом. Возможности выбора - это временные интервалы, которые необходимо выбрать (например, AM / PM / AD / AL), в то время как текущий заказ имеет множество свойств, одно из которых относится ко времени Pickable и показывает выбранную часть дня (ага - поэтому я и написал таймфреймы). Мне нужно привязать элементы поля со списком к набору типа A и выбрать элемент на основе свойства типа B (и его вложенного свойства типа A ). Является ли это возможным?   -  person Konrad Viltersten    schedule 22.01.2015
comment
@KonradViltersten Извините, я не собирался заменять ItemsSource на DataContext. Я намеревался использовать оба рядом друг с другом. Полный пример: ‹ComboBox x: Name = Picky ItemsSource = {x: Static local: MainWindow.AllPickables} DataContext = {Binding CurrentThing} SelectedItem = {Binding Picked} ... /›.   -  person Herman Cordes    schedule 22.01.2015
comment
@HermanCordes Я пробовал то, что вы написали. К сожалению, он еще не прошел до конца. Я исследовал все содержимое окна вывода, и нет никакой информации о каких-либо ошибках. Единственное, что намекает на то, что что-то не так, - это тот факт, что когда я ввожу атрибут DataContext, intellisense вообще ничего не дает мне из модели представления. Ни одной штуки оттуда. У меня есть экземпляр модели vie, назначенный в качестве контекста данных для самого окна. Может ли это вызвать столкновение? Если да, могу ли я каким-то образом получить доступ к контексту данных MainWindow и выполнить привязку к нему?   -  person Konrad Viltersten    schedule 22.01.2015
comment
См. stackoverflow.com/help/mcve   -  person Peter Duniho    schedule 22.01.2015
comment
@KonradViltersten Я бы не стал слишком беспокоиться о Intellisense DataContext (пока). Чтобы ответить на ваш 1-й вопрос: обычно это не вызывает столкновения. 2-й: если ваше поле со списком является дочерним элементом элемента ‹Window› в MainWindow, у него уже есть правильный DataContext. Образец, который я вам дал, должен сузить DataContext для ComboBox, но, очевидно, этого недостаточно. Можно ли обновить свой вопрос с помощью модели просмотра MainWindow, присвоения модели просмотра MainWindow и кода MainWindow за файлом (например, свойство AllPickables).   -  person Herman Cordes    schedule 23.01.2015
comment
@HermanCordes Отличное разъяснение. И да, я могу это сделать. Я только что добавил. Надеюсь, это внесет ясность и устранит любую путаницу, которую я мог вызвать. Поскольку это кажется трудным, и люди недооценили его сложность (возможно, из-за недостаточности предоставленной информации, никакой игры в обвинения не предполагается), я назначаю награду за нее в знак признательности за ваши усилия.   -  person Konrad Viltersten    schedule 23.01.2015
comment
Пожалуйста, покажите class Thing   -  person DrKoch    schedule 26.01.2015


Ответы (2)


Похоже, что сравнение не удается при чтении модели представления. Вероятно, это происходит из-за неправильной / отсутствующей реализации методов сравнения. Попробуйте реализовать Equals и GetHash и посмотрите, работает ли это.

public override bool Equals(Object input)
{
  return Id == ((Thing)input)?.Id;
}

public override int GetHashCode()
{
  return base.GetHashCode();
}
person SebastianC    schedule 26.01.2015

Для ComboBox в WPF важно, чтобы SelectedItem был установлен для объекта, присутствующего в ItemsSource, в вашем случае в IEnumerable<PickType> AllPickables и в XAML ItemSource должен быть расположен до SelectedItem (поскольку он у вас уже есть)

В то время, когда ComboBox видит SelectedItem, он должен присутствовать в его Items. Это правило применяется и в более позднее время, то есть при срабатывании NotifyPropertyChanged.

Далее: CurrentThing должен иметь тот же тип PickType

public PickType CurrentThing { ... }

и CurrentThing должен указывать на один существующий член в AllPickables (или установить значение null, чтобы не было выбора).

person DrKoch    schedule 26.01.2015