【问题标题】:Getting Items From Within ItemsControl (Understanding DataContext)从 ItemsControl 中获取项目(了解 DataContext)
【发布时间】:2015-04-12 03:36:13
【问题描述】:

我正在用各种元素填充ItemsControl,包括ButtonsComboBox 元素。访问和填充元素很简单,但我不知道如何检测和关联ItemsControl 中的ItemComboBox(或Button)属于哪个Item

为了帮助说明问题,请考虑以下基本 UI:

现在,当我使用 ComboBoxButton 时,我希望能够仅将其与 ItemControl Item 关联起来。但是,目前,如果我在ComboBox 中选择一个项目,ItemsControl 中的每个ComboBox 都会反映该更改。

我可以在下面的列表框中捕获SelectedItem,但理想情况下,我希望能够同时显示SelectedItem 和它来自哪个ItemControl Item。例如,ComboBoxItem1, My First Property - From Item (1)

我严格遵守 MVVM 原则,因此,我不寻找任何使用代码隐藏的解决方案。

TL;DR

我知道代码可能会变得笨拙。我相信上面的描述足以说明我的问题,但我在下面包含了基本的样板代码,以防它有助于发布答案。 (显然,我已经在别处实现了INotifyPropertyICommand):

MainWindowView.xaml

<ItemsControl  Width="300" Height="200" ItemsSource="{Binding MyObservableCollection}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="2" Margin="10">
                <StackPanel Margin="0,10,0,10">
                    <TextBlock Margin="10,0,0,0" Text="{Binding MyProperty}" FontWeight="Bold"/>
                    <ComboBox Width="270" Text="myBox" ItemsSource="{Binding DataContext.ComboOptions, RelativeSource={RelativeSource AncestorType=ItemsControl}}" DisplayMemberPath="ListItem" SelectedItem="{Binding DataContext.SelectedItem, RelativeSource={RelativeSource AncestorType=Window}}"/>
                    <RadioButton Width ="270" Content="Button1" Command="{Binding DataContext.GetButtonCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" CommandParameter="Button1" Style="{DynamicResource {x:Type ToggleButton}}"/>
                </StackPanel>
            </Border>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

MyComboBoxOptionsViewModel.cs

public class MyComboBoxOptionsViewModel : ObservableObject
{
    private MyComboBoxOptionsModel _myComboBoxOptions = new MyComboBoxOptionsModel();

    public MyComboBoxOptionsViewModel(MyComboBoxOptionsModel _myComboBoxOptions)
    {
        this._myComboBoxOptions = _myComboBoxOptions;
    }

    public string ComboBoxOption
    {
        get { return _myComboBoxOptions.ComboBoxOption; }
        set
        {
            _myComboBoxOptions.ComboBoxOption = value;
            RaisePropertyChangedEvent("ComboBoxOption");
        }
    }
}

MyComboBoxOptionsModel.cs

public class MyComboBoxOptionsModel
{
    public string ComboBoxOption { get; set; }
}

MainWindowViewModel.cs

public class MainWindowViewModel : ObservableObject
{
    private ObservableCollection<string> _messages = new ObservableCollection<string>();
    private ObservableCollection<MyViewModel> _myObservableCollection = new ObservableCollection<MyViewModel>();
    private List<MyComboBoxOptionsViewModel> _comboOptions = new List<MyComboBoxOptionsViewModel>();
    private MyComboBoxOptionsViewModel _selectedItem = new MyComboBoxOptionsViewModel(null);

    public MainWindowViewModel()
    {
        _myObservableCollection.Add(new MyViewModel(new MyModel { MyProperty = "My First Property" }));
        _myObservableCollection.Add(new MyViewModel(new MyModel { MyProperty = "My Second Property" }));

        _comboOptions.Add(new MyComboBoxOptionsViewModel(new MyComboBoxOptionsModel { ComboBoxOption = "Option1" }));
        _comboOptions.Add(new MyComboBoxOptionsViewModel(new MyComboBoxOptionsModel { ComboBoxOption = "Option2" }));
        _comboOptions.Add(new MyComboBoxOptionsViewModel(new MyComboBoxOptionsModel { ComboBoxOption = "Option3" }));
    }

    public MyComboBoxOptionsViewModel SelectedItem
    {
        get { return _selectedItem; }
        set
        {
            _selectedItem = value;
            _messages.Add(_selectedItem.ComboBoxOption);
            RaisePropertyChangedEvent("SelectedItem");
        }
    }

    public List<MyComboBoxOptionsViewModel> ComboOptions
    {
        get { return _comboOptions; }
        set
        {
            if (value != _comboOptions)
            {
                _comboOptions = value;
                RaisePropertyChangedEvent("ComboOptions");
            }
        }
    }

    public ObservableCollection<MyViewModel> MyObservableCollection
    {
        get { return _myObservableCollection; }
        set
        {
            if (value != _myObservableCollection)
            {
                _myObservableCollection = value;
                RaisePropertyChangedEvent("MyObservableCollection");
            }
        }
    }

    public ObservableCollection<string> Messages
    {
        get { return _messages; }
        set
        {
            if (value != _messages)
            {
                _messages = value;
                RaisePropertyChangedEvent("Messages");
            }
        }
    }
}

【问题讨论】:

    标签: c# wpf mvvm data-binding datacontext


    【解决方案1】:

    我正在查看您想要的 UI,并认为您基本上需要一个包含项目视图模型集合的主视图模型。

    在该项目视图模型中创建一个命令和一个选定项目属性,您可以在模板中将其绑定到组合框和按钮。这为您提供了与组合框值的单个实例的严格 mvvm 绑定以及由按钮的单个实例执行的命令。

    您的组合框项绑定将需要一个显式源作为绑定的一部分,以便您可以从主视图模型挂钩到一个值集合。或者将一个集合添加到您的项目视图模型中,并保持它们干净整洁。

    正如你提到的,你的代码非常详细——这很棒——但我可能错过了它的其他含义。

    抱歉,如果这是对错误问题的回答:)

    【讨论】:

    • 我现在了解如何将每个 ComboBox/Button 视为一个单独的实例,但我仍然不确定如何将更新传递给另一个 ViewModel(在上面的示例中,以填充下部列表框)。基本上,我试图弄清楚以下句子:“然后,您的组合框项绑定将需要一个显式源作为绑定的一部分,这样您就可以从主视图模型挂钩到一个值集合。或者添加一个集合到您的项目视图模型,并保持一切干净整洁。”
    • 您的集合视图模型可以包含组合框的源数据并且您绑定到该组合框(在每个对象中重复相同的集合)。或者您使用父控件数据上下文作为源创建绑定。
    猜你喜欢
    • 2011-12-04
    • 1970-01-01
    • 2013-08-29
    • 2015-04-04
    • 2012-07-25
    • 2011-02-03
    • 1970-01-01
    • 2014-07-30
    • 2010-12-03
    相关资源
    最近更新 更多