在DataTemplate中找到文本框



在datatemplate中有一些元素,我需要在事件处理程序背后的代码中访问。
如果按钮和文本框具有相同的父级,则有效。
我如何处理更复杂的布局?
如果有一般的方法可以访问DatateMplate中的元素?

xaml

<DataTemplate x:Key="fieldDateTemplate">
    <StackPanel>
        <DatePicker SelectedDate="{Binding Path=FieldValue}" />
        <TextBox x:Name="tbFindMe" Text="findME"/>
        <Button Content="FindTB" Click="FindTB_click" Width="60" HorizontalAlignment="Left"/>
    </StackPanel>
</DataTemplate>

c#

private void FindTB_click(object sender, RoutedEventArgs e)
{
    Button btn = (Button)sender;
    TextBox tb = ((StackPanel)btn.Parent).FindName("tbFindMe") as TextBox;
}

必须更新DKOZL提供的出色答案
如果模板中有一个listBox或ListView,那将停止
,那将失败这是现在正常工作的修复程序

private DataTemplate FieldTemplateDetail2(object sender, out ContentPresenter cp)
{
    cp = null;
    if (sender == null) return null;
    var d = sender as DependencyObject;
    DependencyObject dNext = null;
    DataTemplate template = null;
    while (d != null)
    {
        if (d is ContentPresenter)
        {
            Debug.WriteLine("FieldTemplateDetail2 d is ContentPresenter" + d.ToString());
            cp = d as ContentPresenter;
        }
        dNext = VisualTreeHelper.GetParent(d);
        if (dNext != null &&  dNext is ListBoxItem)
        {
            Debug.WriteLine("FieldTemplateDetail2 dNext is ListBoxItem " + d.ToString());
            if (cp != null)
            {
                Debug.WriteLine("FieldTemplateDetail2 cp != null" + cp.ToString());
                cp = cp.ContentTemplate.FindName("fieldTemplateDetail", cp) as ContentPresenter;
                if (cp != null)
                {
                    Debug.WriteLine("FieldTemplateDetail2 cp fieldTemplateDetail != null" + cp.ToString());
                    template = cp.ContentTemplate;
                    if (template == null && cp.ContentTemplateSelector != null)
                        template = cp.ContentTemplateSelector.SelectTemplate(cp.Content, cp);
                    break;
                }
                cp = null;
            }
        }
        //d = VisualTreeHelper.GetParent(d);
        d = dNext;
    }
    return template;
}

基于下面的所有代码,这似乎是基于DKOZL的答案的修复程序
将结核病埋在膨胀中的网格中,这比上面的简单示例

要困难得多
var d = sender as DependencyObject;
ContentPresenter cp = null;
while (d != null && !(d is ListBoxItem))
{
    if (d is ContentPresenter) cp = d as ContentPresenter;
    d = VisualTreeHelper.GetParent(d);
}
if (cp != null) cp = cp.ContentTemplate.FindName("fieldTemplateDetail", cp) as ContentPresenter;
if (cp != null)
{               
    var template = cp.ContentTemplate;
    if (template == null && cp.ContentTemplateSelector != null)
        template = cp.ContentTemplateSelector.SelectTemplate(cp.Content, cp);
    if (template != null)
    {
        var tb = template.FindName("tbFindMe", cp) as TextBox;
        if (tb == null) MessageBox.Show("null", "ContentTemplateSelector");
        else  MessageBox.Show(tb.Text, "ContentTemplateSelector");
    }
}

所有代码按要求

<Window x:Class="ListViewTemplateSelectorWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ListViewTemplateSelectorWPF"
        DataContext="{Binding RelativeSource={RelativeSource self}}"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="bvc" />
        <local:FieldTemplateSelector x:Key="fieldTemplateSelector"/>
        <DataTemplate x:Key="windowTemplate">
            <TextBox x:Name="windowTemplateTB" Text="windowTemplate" />
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <ListBox Grid.Row="0" x:Name="lbFields"
                 ItemsSource="{Binding Path=Fields}"
                 HorizontalContentAlignment="Stretch">
            <ListBox.Resources>
                <DataTemplate x:Key="fieldStringTemplate">
                    <StackPanel x:Name="fieldString" Visibility="Visible">
                        <TextBox Text="{Binding Path=FieldValue}" />
                    </StackPanel>
                </DataTemplate>
                <DataTemplate x:Key="fieldDateTemplate">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <DatePicker Grid.Row="0" SelectedDate="{Binding Path=FieldValue}" />
                        <!--<TextBox Grid.Row="1" x:Name="tbFindMe" Text="findME"/>
                        <Button Grid.Row="2" Content="FindTB" Click="FindTB_click" Width="60" HorizontalAlignment="Left"/>-->
                        <Expander Grid.Row="1" Header="Find">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="auto"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <TextBox Grid.Row="0" x:Name="tbFindMe" Text="findME"/>
                                <Button Grid.Row="1" Content="FindTB" Click="FindTB_click" Width="60" HorizontalAlignment="Left"/>
                            </Grid>
                        </Expander>
                    </Grid>
                </DataTemplate>
            </ListBox.Resources>
            <ListBox.ItemTemplate>
                <DataTemplate DataType="local:Field">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="60"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path=Name}" />
                        <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=DisplayValue}" />                   
                        <ContentPresenter Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
                                    Visibility="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},
                                                         Path=IsSelected, Converter={StaticResource bvc}}"
                                    x:Name="fieldTemplateDetail"
                                    Content="{Binding}"
                                    ContentTemplateSelector="{StaticResource fieldTemplateSelector}"/>                   
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Grid.Row="1" x:Name="findButton" Content="Waste Button" Width="100" HorizontalAlignment="Left" Click="click_Unselect"/>
    </Grid>
</Window>
using System.ComponentModel;
namespace ListViewTemplateSelectorWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    /// 
    public partial class MainWindow : Window
    {
        private List<Field> fields = new List<Field>();
        public MainWindow()
        {
            fields.Add(new FieldString("String1"));
            fields.Add(new FieldString("String2"));
            fields.Add(new FieldDate("Date1"));
            fields.Add(new FieldDate("Date2"));
            InitializeComponent();          
        }
        public Field CurField { get; set; }
        public List<Field> Fields { get { return fields; } }
        private void click_Unselect(object sender, RoutedEventArgs e)
        {            
            try
            {
                Button tb = this.FindName("findButton") as Button;
                if (tb == null) MessageBox.Show("null");
                else MessageBox.Show(tb.Name);
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message, "exception findButton");
            }
            try
            {
                DataTemplate dt = this.FindResource("fieldDateTemplate") as DataTemplate;
                if (dt == null) MessageBox.Show("dt not found");
                else MessageBox.Show("dt found");
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message, "exception dt");
            }
            lbFields.SelectedIndex = -1;
        }
        private void FindTB_click(object sender, RoutedEventArgs e)
        {
            var d = sender as DependencyObject;
            while (d != null && !(d is ContentPresenter)) d = VisualTreeHelper.GetParent(d);
            var cp = d as ContentPresenter;
            if (cp != null)
            {
                var template = cp.ContentTemplate;
                if (template == null && cp.ContentTemplateSelector != null)
                    template = cp.ContentTemplateSelector.SelectTemplate(cp.Content, cp);
                if (template != null)
                {
                    var tb = template.FindName("tbFindMe", cp) as TextBox;
                    MessageBox.Show(tb.Text, "ContentTemplateSelector");
                }
            }
            Button btn = (Button)sender;
            //MessageBox.Show("button name = " + btn.Name);
            try
            {
                TextBox tb = ((Grid)btn.Parent).FindName("tbFindMe") as TextBox;
                if (tb == null) MessageBox.Show("null","manual");
                else MessageBox.Show(tb.Text, "manual");
            }
            catch (Exception Ex)
            {
                MessageBox.Show(Ex.Message, "exception manual");
            }
        }
    }
    public abstract class Field : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
        private string name;
        public string Name { get { return name; } }
        public abstract string DisplayValue { get; }
        public Field(string Name) { name = Name; }
    }
    public class FieldString : Field
    {
        private string fieldValue;
        public string FieldValue
        {
            get { return fieldValue; }
            set
            {
                if (fieldValue == value) return;
                fieldValue = value;
                NotifyPropertyChanged("FieldValue");
                NotifyPropertyChanged("DisplayValue");
            }
        }
        public override string DisplayValue
        {
            get { return FieldValue; }
        }
        public FieldString(string Name) : base(Name) { }
        public FieldString(string Name, string FieldValue) : base(Name)
        {   fieldValue = FieldValue; } 
    }
    public class FieldDate : Field
    {
        private  DateTime? fieldValue = null;
        public DateTime? FieldValue
        {
            get { return fieldValue; }
            set
            {
                if (fieldValue == value) return;
                fieldValue = value;
                NotifyPropertyChanged("FieldValue");
                NotifyPropertyChanged("DisplayValue");
            }
        }
        public override string DisplayValue
        {
            get { return FieldValue.ToString(); }
        }
        public FieldDate(string Name) 
            : base(Name) { }
        public FieldDate(string Name, DateTime FieldValue)
            : base(Name)
        { fieldValue = FieldValue; }
    }
    public class FieldTemplateSelector : DataTemplateSelector
    {
        public override DataTemplate
            SelectTemplate(object item, DependencyObject container)
        {
            FrameworkElement element = container as FrameworkElement;
            if (item != null && item is Field)
            {
                System.Diagnostics.Debug.WriteLine("Field");
                if (item is FieldString)
                {
                    System.Diagnostics.Debug.WriteLine("FieldString");
                    return element.FindResource("fieldStringTemplate") as DataTemplate;
                }
                if (item is FieldDate)
                {
                    System.Diagnostics.Debug.WriteLine("FieldDate");
                    return element.FindResource("fieldDateTemplate") as DataTemplate;                }
                return element.FindResource("fieldTemplate") as DataTemplate;
            }
            else
                return element.FindResource("fieldTemplate") as DataTemplate;
        }
    }
}

要在 DataTemplate中查找按名称的控件,您需要查找使用此模板的ContentPresenter,并在该模板上调用ContentPresenter

在该模板上调用FindName
private void Button_Click(object sender, RoutedEventArgs e)
{
   var d = sender as DependencyObject;
   ContentPresenter cp = null;
   while (d != null && !(d is ListBoxItem))
   {
       if (d is ContentPresenter) cp = d as ContentPresenter;
       d = VisualTreeHelper.GetParent(d);
   }
   if (cp != null)
   {
      cp = cp.ContentTemplate.FindName("fieldTemplateDetail", cp) as ContentPresenter;
      if (cp != null)
      {
         var template = cp.ContentTemplate;
         if (template == null && cp.ContentTemplateSelector != null)
            template = cp.ContentTemplateSelector.SelectTemplate(cp.Content, cp);
         if (template != null)
         {
            var tb = template.FindName("tbFindMe", cp) as TextBox;
         }
      }
   }
}

这个较旧的帖子一直是救生员。过去几个小时我一直在解决这个问题,DKOZL提供了一些很好的见解。希望我的解释能帮助其他一些。

我有一个具有一些列的数据杂题(确切地说是7列),其中5列在项目上显示静态数据,1是文本框条目/数据显示,最后一个是boolean项目的on和off指标。

我当前在使用datagrid时正在改善用户体验(使用F2编辑,切换布尔值等等)

下面的XAML我将在DataGrid中只有一个带有文本框的列:

<DataGrid x:Name="my_DG" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AutoGenerateColumns="False" KeyDown="my_DG_KeyDown">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <TextBlock Text="Value" FontSize="18"/>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBox x:Name="txtBoxValue" Text="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" KeyDown="EventTrigger_KeyDown"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellStyle>
                <Style TargetType="DataGridCell">
                    <Setter Property="IsTabStop" Value="False" />
                </Style>
            </DataGridTemplateColumn.CellStyle>
        </DataGridTemplateColumn>
    <DataGrid.Columns>
</DataGrid>

我要遇到的效果是当我推出f2焦点时,我在数据杂志上突出显示了一排,用户可以开始编辑该值。这是通过keydown =" my_dg_keydown"事件完成的。事件中的代码是:

private void my_DG_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key.Equals(Key.F2))
    {
        var currRow = (sender as DataGrid).CurrentItem;
        //Columns[0] is the column the text box is in for the given row.
        var currCell_CP = (sender as DataGrid).Columns[0].GetCellContent(currRow);
        var itm = (currCell_CP as ContentPresenter).ContentTemplate.FindName("txtBoxValue", currCell_CP) as TextBox;
        itm.Focus();
    }
}

重要的取消是我能够获得给定单元的内容。然后从那里我能够获得模板并搜索这两个项目的文本框名称(" txtboxvalue")。

我发现这比dkozl的答案更加直接,但是没有他的帮助,我不会来

相关内容

  • 没有找到相关文章

最新更新