如何获取模板组合框的值

时间:2015-02-04 10:33:23

标签: c# wpf

我在这里有一个模板组合框

<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;
}

组合框将加载:

enter image description here

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

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

2 个答案:

答案 0 :(得分:1)

将Button绑定到ViewModel中的ICommand-Property并将所选项目作为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-Declaration中的部分:DataContext="{Binding RelativeSource={RelativeSource Self}}"通过这个,你告诉Window它的DataContext在CodeBehind-File中。您还可以使用另一个File作为DataContext。比你必须写:

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

这仅适用于将xmlns:loc="clr-namespace:YOURPROJECTNAMESPACE"添加到Window-Declaration中的情况。在我的演示的情况下,YOURPROJECTNAMESPACE将是ComboBoxDemo。

我还为参数创建了一个非常简单的类,如下所示:

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

Window的CodeBehind(记住:这是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,如果你使用命令绑定,你可能总是需要它。这是班级RelayCommand。这个类有一个构造函数,它需要一个Action<object>类型的对象。稍后此操作包含单击按钮时将执行的操作。 seconde可选参数我现在不解释。 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具有您给定的Itemtemplate。在ComboBox的定义中,我添加了ItemsSource="{Binding Parameters, UpdateSourceTrigger=PropertyChanged}"。这告诉ComboBox它将从这个位于VM中的集合中获取它的子节点。

VM中的集合是ObservableCollection<Parameter>。这种类型的Collection的优点是,它实现了ICollectionChanged-Interface,因此如果在此集合中添加或删除了项目,V将会更新。

V中的Button只是将一个虚拟参数添加到ObservableCollection<Parameter>

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

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

我希望这会对你有所帮助。

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

答案 1 :(得分:1)

一种快速的方法是简单地将按钮的Tag属性绑定到与TextBlock相同的属性。

<Button Tag="{Binding Path=Id}" />

然后在按钮点击事件的事件处理程序中,您可以将发件人强制转换为Button并从Tag属性中获取ID。

int id = Convert.ToInt32((sender as Button).Tag);