如何获取模板组合框的值

How to get the value of a template combo box

我得到了一个模板组合框

<ComboBox x:Name="TryCombo" >
    <ComboBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">

                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition Width="200"/>
                        <ColumnDefinition Width="75"/>
                    </Grid.ColumnDefinitions>

                    <TextBlock Text="{Binding Path=Id}" Margin="4,0" Visibility="Collapsed" Grid.Column="0"/>
                    <TextBlock Text="{Binding Path=Name}" Margin="4,0" Grid.Column="1"/>
                    <Button x:Name="AddButton" Content="Add"  Grid.Column="2"/>
                </Grid>


            </StackPanel>
        </DataTemplate>
    </ComboBox.ItemTemplate>


</ComboBox>

然后是 ItemsSource:

public void BindComboboxes()
{

    itemMgr.Parameters = RetrieveFilter("");
    itemMgr.EntityList = itemMgr.RetrieveMany(itemMgr.Parameters);

    TryCombo.ItemsSource = itemMgr.EntityList; //collection;
}

组合框将载入:

我的问题是获取我用 AddButton 单击的选定项目,我想获取绑定到 Path=Id 的文本块的值,但是如何?

我应该为每个 TextBlocks 添加 x:Name 吗?

将您的 Button 绑定到 ViewModel 中的 ICommand-属性 并将所选项目作为 CommandParameter

传递

我为您制作了一个小型演示应用程序:

MainWindow.xaml 看起来像:

<Window x:Class="ComboBoxDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        WindowStartupLocation="CenterScreen"
        DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Button Content="Add Item to ComboBox" Margin="5" Command="{Binding AddItemCommand}"/>
        <ComboBox Grid.Row="1" x:Name="TryCombo" ItemsSource="{Binding Parameters, UpdateSourceTrigger=PropertyChanged}" Margin="5">
            <ComboBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="50"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock Text="{Binding Path=Id}" Margin="4,2" VerticalAlignment="Center" Grid.Column="0"/>
                            <TextBlock Text="{Binding Path=Name}" Margin="4,2" Grid.Column="1" VerticalAlignment="Center"/>
                            <Button x:Name="AddButton" Content="Add" Grid.Column="2" VerticalAlignment="Center" Margin="4,2"
                                    Command="{Binding DataContext.ComboBoxItemAddCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"
                                    CommandParameter="{Binding}"/>
                        </Grid>
                    </StackPanel>
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </Grid>
</Window>

重要的是 Window 声明中的部分:DataContext="{Binding RelativeSource={RelativeSource Self}}" 通过这个你告诉 Window 它的 DataContext 在代码隐藏文件中。您还可以使用另一个文件作为您的 DataContext。比你必须写:

<Window.DataContext>
  <loc:MyClassName/>
</Window.DataContext>

这仅在您将 xmlns:loc="clr-namespace:YOURPROJECTNAMESPACE" 添加到 Window 声明时有效。对于我的演示,YOURPROJECTNAMESPACE 将是 ComboBoxDemo。

我还为参数创建了一个 class,它非常简单,看起来像:

public class Parameter
{
    public string Id { get; set; }
    public string Name { get; set; }
}

Window 的代码隐藏(记住:这是 MainWindow.xaml 的 DataContext)看起来像:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Input;

namespace ComboBoxDemo
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private ICommand addItemCommand;
        private ICommand comboBoxItemAddCommand;
        private ObservableCollection<Parameter> parameters;

        public MainWindow()
        {
            InitializeComponent();
            Parameters = new ObservableCollection<Parameter>();
            AddItemCommand = new RelayCommand(AddItem);
            ComboBoxItemAddCommand = new RelayCommand(ComboBoxItemAdd);
        }

        private void ComboBoxItemAdd(object parameter)
        {
            Parameter para = parameter as Parameter;
            if (para != null)
            {
                // Now you can use your Parameter
            }
        }

        public ObservableCollection<Parameter> Parameters
        {
            get { return parameters; }
            set
            {
                parameters = value;
                OnPropertyChanged();
            }
        }

        public ICommand AddItemCommand
        {
            get { return addItemCommand; }
            set
            {
                addItemCommand = value;
                OnPropertyChanged();
            }
        }

        public ICommand ComboBoxItemAddCommand
        {
            get { return comboBoxItemAddCommand; }
            set
            {
                comboBoxItemAddCommand = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void AddItem(object parameter)
        {
            Parameters.Add(new Parameter
            {
                Id = Guid.NewGuid().ToString(),
                Name = "Any Name"
            });
        }

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我还创建了一个非常有用的 Helper-Class 如果您使用命令绑定,您可能总是需要它。这是classRelayCommand。这个 class 有一个构造函数,它需要一个 Action<object> 类型的对象。此操作稍后包含单击按钮时将执行的操作。第二个可选参数我现在不解释。 RelayCommand 看起来像:

using System;
using System.Windows.Input;

namespace ComboBoxDemo
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> execute;
        private readonly Predicate<object> canExecute;

        public RelayCommand(Action<object> execute, Predicate<object> canExecute = null )
        {
            if (execute == null)
                throw new ArgumentNullException("execute");
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            if (canExecute == null)
                return true;
            return canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            execute(parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }
    }
}

所以。现在我将向您解释该过程:因此,我使用以下缩写

  • V = MainWindow.xaml
  • VM = MainWindow.xaml.cs

V 中的 ComboBox 有您给定的项目模板。在 ComboBox 的定义中,我添加了 ItemsSource="{Binding Parameters, UpdateSourceTrigger=PropertyChanged}"。这告诉 ComboBox 它将从位于 VM 中的这个集合中获取它的子项。

VM 中的集合是 ObservableCollection<Parameter>。这种类型的集合的优点是,它实现了 ICollectionChanged 接口,因此如果有项目添加到此集合或从中删除,您的 V 将得到更新。

V 中的按钮只是向 ObservableCollection<Parameter> 添加了一个虚拟参数。

使用 Command="{Binding AddItemCommand}" 我告诉按钮它的命令-属性 绑定到 DataContext 中的 AddItemCommand。在 DataContext (MainWindow.xaml.cs) 的构造函数中,我正在创建此命令并提供将在执行命令时调用的 AddItem-Method。

DataTemplate 中的 Button 绑定必须提供一个 RelativeSource 因为在 Template 中 DataContext 是另一个。使用 RelativeSource 我可以告诉 Button 它的 Command-属性 绑定到位于 Window.

的 DataContext 中的命令

希望对您有所帮助。

如果您想更深入地了解 MVVM 模式,请查看 this Link

一个快速的方法是将按钮的 Tag 属性 绑定到与 TextBlock.

相同的 属性
<Button Tag="{Binding Path=Id}" />

然后在按钮单击事件的事件处理程序中,您可以将发送者转换为 Button 并从 Tag 属性.

中获取 ID
int id = Convert.ToInt32((sender as Button).Tag);