1

我需要从我的ComboBoxes 中获取值,这些值驻留ObservableCollectionItemsControl. 而且我需要将它们存储在一个单独的数据结构中,至少我认为是这样。听起来很简单?我希望是这样,我整天都在坚持。

这是我的 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}"/>

where 在IVCollection这里定义,在我的 ViewModel 中:

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

    ...
}

在你问是什么之前ExternalClass,要知道那是包含Variable和的东西Values

这就是问题所在。我需要得到SelectedIndexof ComboBox(所以我会改变当前的代码SelectedIndex="0")。如果我ExternalClass需要包含这些SelectedIndex值,那将很容易,因为我已经可以访问它的字段(VariableValue)。但我需要这些int价值观

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

    ...
}

或类似的东西。我已经制作了一个快速包装类来同时包含SelectedIndicesand IVCollection,但显然这不起作用,因为ItemsControl想要一个ObservableCollection,而不是一个有两个ObservableCollections 的类。

而且我想这里问题的真正实质(我可能是错的,这就是我要问的原因)是我如何访问我当前所在的Style/范围之外的属性(例如)?我可以在代码隐藏中毫无问题地做到这一点,就像这样,DataTemplateIVCell

    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 等一起使用,但这只是推迟了问题。我需要解决它。或者绕过它。

4

3 回答 3

2

我会这样做,我会为所选值创建一个属性

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

然后将SelectedItemin绑定ComboBoxSelectedObject属性

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

希望这会有所帮助

于 2013-02-08T21:24:23.607 回答
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 友好的方式。

于 2013-02-08T21:47:56.480 回答
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}"/>
于 2013-02-11T18:08:07.573 回答