获取控件的Tag值

时间:2017-08-04 09:04:57

标签: c# wpf

基于此XAML

<ListView>
    <ListView.View>
        <GridView>
            <GridViewColumn>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal"
                                    VerticalAlignment="Center"
                                    HorizontalAlignment="Center">
                            <TextBlock Text="{Binding ProductDescription}"/>
                         </StackPanel>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn>
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal"
                                    VerticalAlignment="Center"
                                    HorizontalAlignment="Center">
                            <TextBox x:Name"txtExchange"
                                     Tag="{Binding ProductBarcode}"/>
                            <Button Content="Add"
                                    Tag="{Binding ProductBarcode}"
                                    Click="SelectExchangeProduct" />
                         </StackPanel>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
        </GridView>
    </ListView.View>
</ListView>

由于插入的所有行都具有相同的TextBox,因此使用x:Name来获取值是不可能的。

我添加了绑定到Tag属性,以便我可以区分所有TextBox。问题是如何才能找到具体的TextBox?我尝试使用FindName(),但我不知道如何使用特定TextBox值获取Tag

我也试过这个:

var txtExchangeQuantity = someParentControl.Children.OfType<TextBox>().Where(x => x.Tag.ToString() == barcode).FirstOrDefault();

但也没用。我看到了Where部分的潜力,但不知道如何实现它。

以下是Click事件:

private void SelectExchangeProduct(object sender, RoutedEventArgs e)
    {
        Button btn = sender as Button;
        string barcode = btn.Tag.ToString();
        var txtExchangeQuantity = grdExchange.Children.OfType<TextBox>().Where(x => x.Tag.ToString() == barcode).FirstOrDefault();

    }

以下是我绑定到的对象(使用ObservableCollection

class TransactionList{
    private string _productBarcode;
    public string ProductBarcode
    {
        get { return _productBarcode; }
        set { _productBarcode = value; }
    }
    private string _productDescription;
    public string ProductDescription
    {
        get { return _productDescription; }
        set { _productDescription = value; }
    }
}

3 个答案:

答案 0 :(得分:1)

在代码中的某处创建ICommand的实现,如下所示:

public class RelayCommand : ICommand
{
    #region Fields
    private Action<object> execute;
    private Predicate<object> canExecute;
    #endregion

    #region Events
    public event EventHandler CanExecuteChanged;
    #endregion

    #region Constructors
    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        this.execute = execute ?? throw new ArgumentException(nameof(execute));
        this.canExecute = canExecute ?? throw new ArgumentException(nameof(canExecute));
    }
    #endregion

    #region Methods
    public void InvokeExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
    public bool CanExecute(object parameter)
    {
        return canExecute(parameter);
    }
    public void Execute(object parameter)
    {
        execute(parameter);
    }
    #endregion
}

然后,您可以在视图模型中实现属性,如

public RelayCommand SelectExchangeProductCommand { get; private set; }

public ViewModel()
{
    SelectExchangeProductCommand = new RelayCommand(SelectExchangeProductExecute, SelectExchangeProductCanExecute);
}

然后实现了两种方法:

public void SelectExchangeProductExecute(object parameter)
{
    // parameter will then be your Barcode
    if(parameter is string barcode)
    {
         // Now you have the barcode available... but you can really bind anything to end up here.
    }
}

public bool SelectExchangeProductCanExeucte(object parameter)
{
     // return true and false accordingly to execution logic. By default, just return true...
    return true;
}

然后你可以在xaml中将Button绑定到这个命令,如下所示:

<DataTemplate>
    <StackPanel Orientation="Horizontal"
            VerticalAlignment="Center"
            HorizontalAlignment="Center">
       <TextBox x:Name"txtExchange" />
       <Button Content="Add" 
               Command="{Binding Source=ViewModel, Path=SelectExchangeProductCommand}" 
               CommandParameter="{Binding ProductBarcode}" />
   </StackPanel>
</DataTemplate>

就像这样,您无需识别ButtonTextBox,只需将相应数据绑定到CommandParameter,模板即可完成其余工作。

答案 1 :(得分:0)

似乎ICommand是要走的路,但对我来说这是一个新概念,所以我会告诉你在我的案例中我会做些什么:

UserControl中的组控件&#34; ExchangeControl&#34;用例如。一个TextBox&#34; txtExchange&#34;,一个Button&#34; btnAdd&#34;和一个事件所以当你点击btnAdd时,你可以完全控制txtExange做一些事情。

在需要时实例化:

someStackPanel.Children.Add(new ExchangeControl() {Content = "SOME TEXT"});

要让上述代码有效,您应该在ExchangeControl类中拥有此属性:

private string content;
public string Content
{
    get { return content; }
    set { content = value; txtExchange.Text = value; }
}

所以......现在你可以通过点击btnAdd来获取txtExchange内容(SOME TEXT),如果你在ExchangeControl类中点击按钮创建了一个事件

只是为了图表,这里是一个向您的按钮添加事件的示例,假设已经有一个带有一些ExchangeControl项目的StackPanel

someStackPanel.Children.Cast<ExangeControl>().ToList().ForEach(ec =>
    ec.btnAdd.Click += (se, a) => MessageBox.Show(ec.txtExchange.Text));

顺便说一句,这里是如何在选中时获取DataGrid中特定TextBox的内容:

string someContent = (yourDataGrid.SelectedItem as TextBox).Text;

答案 2 :(得分:-2)

使用VisualTreeHelper按类型获取子项更容易。

How to get children of a WPF container by type?