user2835256
user2835256

Reputation: 415

ItemsControl TextBox Name is not Working in .cs File

My WPF Application code generates panels on function call defined in .cs file. There is ItemControl used in code to generates these Panels . I want to Name Textbox defined in this ItemControl and to use this in code. I named it as textEdit1 and used it in code but code generated error that textEdit1 doesn't exist. Can anyone solve my problem? Here Code is:

XAML File:

<dxlc:ScrollBox>
    <ItemsControl Name="lstPanels">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="vertical">
                    <Grid>
                        <dxe:TextEdit Height="165" Text="{Binding Text,
                                    Mode=TwoWay}" x:Name="textEdit1"/>
                    </Grid>
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</dxlc:ScrollBox>

.CS FILE

public partial class Window1 : Window
{
    string valuu;
    public Window1()
    {
        InitializeComponent();
        addPanel("Header1");
        addPanel("Header2");
        addPanel("Header3");
        lstPanels.ItemsSource = panels;

    }
    public ObservableCollection<MyPanel> panels = new ObservableCollection<MyPanel>();
    public void addPanel(string buttonId)
    {
        MyPanel p = new MyPanel { Id = buttonId};
        panels.Add(p); 
        functionb(p);
    }
    public void functionb(MyPanel obj)
    {        
        valuu = obj.Text;            
    }

    private void button2_Click(object sender, RoutedEventArgs e)
    {
        foreach (var f in panels.ToList())
        {
            MessageBox.Show( f.Id + "   ***   "  + f.Text);
        }
    }
}

public class MyPanel : INotifyPropertyChanged
{
    private string _id;
    private string _text;

    public string Id
    {
        get { return _id; }
        set
        {
            if (value != _id)
            {
                _id = value;
                NotifyPropertyChanged();
            }
        }
    }
    public string Text
    {
        get { return _text; }
        set
        {
            if (value != _text)
            {
                _text = value;
                NotifyPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(  String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Upvotes: 1

Views: 545

Answers (2)

Daniel Gruszczyk
Daniel Gruszczyk

Reputation: 5622

I see that you are using some 3rd party libraries for your TextBox and ScrollBox. If you provide me with the names of the libraries, I could have a look at them as the functionality might be different from what WPF has out-of-the-box.
As for now you have 3 options (I am giving examples for standard TextBox and ItemsControl):

I) You do not have to access the textbox at all.
An easy way around it is described here: StackOverflow post

II) Handling events and references to TextBoxes in the code behind

  1. Add a Loaded event to your TextBox:

    <TextBox x:Name="txtText" Width="300" Height="100" Loaded="txtText_Loaded" />
    
  2. Add a field to your MyPanel class to hold a reference to a TextBox:

    public class MyPanel
    {
        public string Text { get; set; }
        public TextBox TextBox { get; set; }
        /* the rest ... */
    }
    
  3. Add a counter to your window, next to a list with panels:

    protected ObservableCollection<MyPanel> panels = new ObservableCollection<MyPanel>();
    private int counter = 0;
    
  4. Handle the Load event of the TextBox:

    private void txtText_Loaded(object sender, RoutedEventArgs e)
    {
        panels[counter].TextBox = (TextBox)sender;
        counter++;
    }
    
  5. If you want to access a particular TextBox, do it this way:

    MessageBox.Show(panels[i].TextBox.Text);
    

III) Add additional bindings for FontSize:

  1. Add a FontSize property to your MyPanel class:

    private double _fontSize = 10;
    public double FontSize
    {
        get { return _fontSize; }
        set
        {
            if (value != _fontSize)
            {
                _fontSize = value;
                NotifyPropertyChanged();
            }
        }
    }
    
  2. Bind just added property to the TextBox in your ItemsControl:

    <TextBox x:Name="txtText" Width="300" Height="100" Text="{Binding Text;, Mode=TwoWay}"
             FontSize="{Binding FontSize, Mode=OneWay}" />
    
  3. Add a slider to the template and bind it to the same property:

    <Slider Minimum="10" Maximum="30" Value="{Binding FontSize, Mode=TwoWay}" />
    

This way if you change the value on a slider, it will change the value in your MyPanel object bound to the panel. This in turn will change the font size of the textbox.

My whole code I tested it on looks like that:

<ItemsControl x:Name="lstItems" >
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Vertical">
                    <TextBox x:Name="txtText" Width="300" Height="100" Text="{Binding Text;, Mode=TwoWay}" FontSize="{Binding FontSize, Mode=OneWay}" />
                    <Slider Minimum="10" Maximum="30" Value="{Binding FontSize, Mode=TwoWay}" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

And code behind:

public partial class MainWindow : Window
{
    protected ObservableCollection<MyPanel> texts = new ObservableCollection<MyPanel>();

    public MainWindow()
    {
        InitializeComponent();

        texts.Add(new MyPanel() { Text = "Test 1" });
        texts.Add(new MyPanel() { Text = "Test 2" });

        lstItems.ItemsSource = texts;
    }
}

public class MyPanel : INotifyPropertyChanged
{
    private string _id;
    private string _text;
    private double _fontSize = 10;

    public string Id
    {
        get { return _id; }
        set
        {
            if (value != _id)
            {
                _id = value;
                NotifyPropertyChanged();
            }
        }
    }
    public string Text
    {
        get { return _text; }
        set
        {
            if (value != _text)
            {
                _text = value;
                NotifyPropertyChanged();
            }
        }
    }
    public double FontSize
    {
        get { return _fontSize; }
        set
        {
            if (value != _fontSize)
            {
                _fontSize = value;
                NotifyPropertyChanged();
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I personally would go with the last solution.
But again, let me know what libraries you are using, and I will have look at them when I have some time. Good luck.

Upvotes: 2

Thomas Levesque
Thomas Levesque

Reputation: 292605

textEdit1 is part of a template that will be instantiated multiple times, so there will be multiple instances of textEdit1. It wouldn't make sense to generate a field for textEdit1 in the class, because it could only refer to one instance the TextEdit control...

Upvotes: 2

Related Questions