我需要通过ComboBox
获取位于ObservableCollection
内的ItemsControl
内的值。我需要将它们存储在一个单独的数据结构中,至少我认为我做了。听起来很简单?我希望是这样,我一直坚持下去。
这是我的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
的内容。
这是问题所在。我需要获取SelectedIndex
的{{1}}(所以我会更改当前代码ComboBox
)。如果我的SelectedIndex="0"
是需要包含这些ExternalClass
值的内容,那就很容易了,因为我已经可以访问其字段(SelectedIndex
和Variable
)。但我需要
Value
个值
int
或类似的东西。我创建了一个包含public class MainViewModel : ViewModelBase
{
public ObservableCollection<int> SelectedIndices { get; set; }
...
}
和SelectedIndices
的快速包装类,但显然这不起作用,因为IVCollection
想要一个ItemsControl
,而不是一个有两个{ {1}}秒。
我想这里问题的真正含义(我可能错了,这就是我要问的原因)是如何访问超出ObservableCollection
/ {{1}范围的属性我现在在(例如ObservableCollection
)?我可以在代码隐藏中完成它,没有问题,就像这样,
Style
但是我再一次尝试保持MVVM友好。我甚至尝试过使用MVVM Light等事件命令,但这只是推迟了问题。我需要解决它。或绕过它。
答案 0 :(得分: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 :(得分: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友好的方式。
答案 2 :(得分: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}"/>