2013-02-08 2 views
1

Мне нужно получить значения из моих ComboBox es, которые находятся в ObservableCollection, итерации через ItemsControl. И мне нужно хранить их в отдельной структуре данных, по крайней мере, я думаю, что знаю. Звучит довольно просто? Надеюсь, я все время застрял на нем.Элемент доступа WPF MVVM внутри ItemsControl DataTemplate

Вот мой XAML:

<Window.Resources> 
    <Style x:Key="IVCell" TargetType="{x:Type ItemsControl}"> 
     <Setter Property="ItemTemplate"> 
      <Setter.Value> 
       <DataTemplate> 
        <StackPanel> 
         <TextBlock Text="{Binding Variable.Name}"/> 
         <ComboBox x:Name="IVValues" ItemsSource="{Binding Values}" 
            SelectedIndex="0"/> 
        </StackPanel> 
       </DataTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

... 
     <ItemsControl Name="IndependentVariables" Style="{StaticResource IVCell}" ItemsSource="{Binding IVCollection}"/> 

где IVCollection определяется здесь, в моем ViewModel:

public class MainViewModel : ViewModelBase 
{ 
    public ObservableCollection<ExternalClass> IVCollection { get; set; } 

    ... 
} 

Прежде чем спросить, что ExternalClass это, знайте, что это то, что содержит Variable и Values.

В этом проблема. Мне нужно получить SelectedIndexComboBox (так что я бы изменил текущий код SelectedIndex="0"). И если мои ExternalClass были такими, которые должны были содержать эти значения SelectedIndex, это было бы легко, так как у меня уже есть доступ к его полям (Variable и Value). Но мне нужны эти int значения в

public class MainViewModel : ViewModelBase 
{ 
    public ObservableCollection<int> SelectedIndices { get; set; } 

    ... 
} 

или что-то в этом роде. Я сделал быстрый класс обертки, содержащий как SelectedIndices, так и IVCollection, но, очевидно, это не сработает, потому что ItemsControl хочет ObservableCollection, а не класс с двумя ObservableCollection.

И я думаю, что настоящее мясо вопроса здесь (я мог ошибаться, вот почему я спрашиваю), как я могу получить доступ к объекту, находящемуся за пределами области Style/DataTemplate Я сейчас в (например IVCell)? Я могу сделать это в коде-за без проблем, как это так,

private void IVValues_OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
    { 
     for (var i = 0; i < IndependentVariables.Items.Count; i++) 
     { 
      var uiElement = IndependentVariables.ItemContainerGenerator.ContainerFromIndex(i); 
      var cBox = FindVisualChild<ComboBox>(uiElement); //Homebrew method 
      //cBox.SelectedIndex 
     } 
    } 

но еще раз, я пытаюсь остаться MVVM дружелюбным. Я даже пытался использовать команды событий с MVVM Light и т. Д., Но это просто откладывает проблему. Мне нужно это решить. Или обойти его.

+0

Так что, если вам удастся связать выбранные значения индекса каждого ComboBox к вам SelectedIndices коллекции, как вы будете отслеживать, какие значения из какой ComboBox/ExternalClass ? Похоже, что длина элементов в IVCollection фиксирована, и поэтому вы намерены использовать индекс значения в SelectedIndices, но я не совсем понятен. –

+0

Вам нужно другое свойство или два в «ExternalClass» для привязки к SelctedItem и/или SelectedIndex ComboBox, чтобы отслеживать, какие элементы выбраны. –

ответ

0

@sleiman и @Brandon Ни один из ваших ответов не был на 100%, но тем не менее они были очень полезны. Я достиг своего решения, используя элементы из обоих ваших ответов, поэтому я не решаюсь принимать один за другим.

Я использовал комбинацию решения класса-оболочки и выставленное решение собственности (наряду с полом-неродственной, но тем не менее необходимой техникой обработки событий), чтобы создать следующее:

public class IVWrapper : INotifyPropertyChanged 
{ 
    public VariableValueList<double> IVCollection { get; set; } 
    private int selectedIndex; 
    public int SelectedIndex 
    { 
     get { return selectedIndex; } 
     set 
     { 
      selectedIndex = value; 
      OnPropertyChanged("SelectedIndex"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string propertyName) 
    { 
     var handler = PropertyChanged; 

     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

и

public class MainViewModel : ViewModelBase 
{ 

    public ObservableCollection<IVWrapper> IVWrapperCollection { get; set; } 

    ... 

    private void InitializeIVs() 
    { 
     IVWrapperCollection.Clear(); 
     foreach (var iv in ...) 
     { 
      var toBeAdded = new IVWrapper {IVCollection = iv}; 
      toBeAdded.PropertyChanged += (sender, args) => Foo(); 
      IVWrapperCollection.Add(toBeAdded); 
     } 
    } 

    public void Foo() 
    { 
     //Doin stuffs 
    } 
} 

Эта дополнительная интеграция с моей ViewModel позволяет мне вызвать функцию всякий раз, когда меняют selectionIndex. Ухоженная! И чистый!

Соответствующие изменения в XAML MainView:

    <StackPanel> 
         <TextBlock Text="{Binding IVCollection.Variable.Name}"/> 
         <ComboBox ItemsSource="{Binding IVCollection.Values}" 
            SelectedIndex="{Binding SelectedIndex}"/> 
        </StackPanel> 

... 

     <ItemsControl Name="IndependentVariables" Style="{StaticResource IVCell}" ItemsSource="{Binding IVWrapperCollection}"/> 
2

Это как бы я это сделать, я бы создать свойство для выбранного значения

// within the MainViewModel class 
private ExternalClass _selectedObject; 
public ExternalClass SelectedObject 
{ 
    get { return _selectedObject; } 
    set 
     { 
      _selectedObject= value; 
      RaisePropertyChanged("SelectedObject"); 
     } 
    } 

, а затем связать SelectedItem в ComboBox к SelectedObject собственности

<ComboBox ItemsSource="{Binding IVCollection}" SelectedItem="{Binding SelectedObject}" > 
     <ComboBox.ItemTemplate> 
      <DataTemplate> 
       ... data template goes here 
      </DataTemplate> 
     </ComboBox.ItemTemplate> 
</ComboBox> 

Надеется, что это будет полезный

+1

'IVCollection' - это коллекция коллекций. Каждый элемент в 'IVCollection' является обязательным для ComboBox; другими словами, ComboBox не привязывается к 'IVCollection', по крайней мере, как описано OP. –

+0

@MetroSmurf Вы правы. Каждый элемент в 'IVCollection' содержит независимую переменную, где каждый IV содержит свое имя и список возможных значений. В соответствии с этим ответом мне понадобится массив или список 'SelectedObject', которые могут быть проанализированы для каждого выбранного значения ComboBox. – Joseph

1

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

В MainWindow, добавьте следующий маршрутизируемую обработчик события где-то, прежде чем ваш взгляд показано, как конструктор или груженого событие:

AddHandler(Selector.SelectionChangedEvent, new SelectionChangedEventHandler(OnSelectionChanged)); 

Затем добавьте этот обработчик:

private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var comboBox = e.OriginalSource as ComboBox; 
    if (comboBox == null) return; 
    var context = comboBox.DataContext as ExternalClass; 
    if (context == null) return; 
    var indexOfContext = IVCollection.IndexOf(context); 
    if (indexOfContext < 0) return; 
    SelectedIndices[indexOfContext] = comboBox.SelectedIndex; 
} 

Я все еще не уверены, как вы планируете следить за тем, какие SelectedIndex отправляются с данными, поэтому в приведенном выше примере я предположил, что для SelectedIndices существует фиксированная длина.

Если вы ищете чистое связывание данных, я настоятельно рекомендую вам просто поместить свойство на ExternalClass и привязать его. Или, если вы против этого, используйте класс оболочки вокруг ExternalClass, который предоставляет ExternalClass как свойство и SelectedIndex как другой. Это будет самый простой и удобный способ MVVM.

+0

Благодарим за ответы. Что касается чистого решения привязки данных, я действительно не могу, поскольку я не могу изменить внешний класс только для этого случая. В противном случае я бы сделал это давным-давно! Что касается решения класса оболочки, если вы ссылаетесь на мой вопрос, вы увидите, что я это пробовал. Проблема заключается в том, что 'ItemsControl' хочет' ObservableCollection', а не пользовательский класс, содержащий 'IVCollection' и' SelectedObject'. С другой стороны, если я превращу 'IVCollection' в' ObservableCollection ', теперь я не знаю, как получить доступ к переменной и значениям 'ExternalClass'. – Joseph

Смежные вопросы