Search code examples
c#wpfxamllambdauicontrol

How to get the other control of WPF having same parent in c# without its name proprty?


I have the following code snippet in XAML.

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="01*"/>
        <ColumnDefinition Width="01*"/>
    </Grid.ColumnDefinitions>

    <TextBlock Grid.Column="1" Text="ABC" Name="txtBlockABC"/>
    <TextBlock Grid.Column="2" Text="DEF"/>
</Grid>

And I want to access the TextBlock with Text = "DEF" in C# through the name of other TextBlock (i.e. txtBlockABC).

I tried the following.

TextBlock txtBlockDEF = (TextBlock) ((Grid) (txtBlock1stPlane.Parent)).Children[1];

But it accesses with its index, not with its Text property.

I want something like Lamba Expression. Like:

TextBlock txtBlockDEF = (List<TextBlock>) ((Grid) (txtBlock1stPlane.Parent)).Children.All().Where(x => x.Text = "DEF").ToList()[0];

Updated:

The purpose of this is to swap the Text of selected TextBlock with its adjacent TextBlock.


Solution

  • The purpose of this is to swap the Text of selected TextBlock with its adjacent TextBlock"

    As I suspected, you definitely are doing it the wrong way.

    You should have a view model. That view model should have two properties that represent the text displayed by your two TextBlock elements. Each elements should bind their Text property to the appropriate view model property. Then when you want to swap the values, you just swap the values on the view model (which you have direct access to).

    Without a good Minimal, Complete, and Verifiable code example it's impossible to provide any sort of specific advice regarding your own code. But here's the basic idea:

    class MyViewModel : INotifyPropertyChanged
    {
        private string _text1;
        private string _text2;
    
        public string Text1
        {
            get { return _text1; }
            set { _UpdateField(ref _text1, value); }
        }
    
        public string Text2
        {
            get { return _text2; }
            set { _UpdateField(ref _text2, value); }
        }
    
        public ICommand SwapValues { get; }
    
        public MyViewModel()
        {
            SwapValues = new SwapValuesCommand(this);
        }
    
        private class SwapValuesComand : ICommand
        {
            private readonly MyViewModel _owner;
    
            public SwapValuesCommand(MyViewModel owner)
            {
                _owner = owner;
            }
    
            public event EventHandler CanExecuteChanged;
    
            public bool CanExecute(object parameter) { return true; }
    
            public void Execute(object parameter)
            {
                string temp = _owner.Text1;
    
                _owner.Text1 = _owner.Text2;
                _owner.Text2 = temp;
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void _UpdateField<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null)
        {
            if (!EqualityComparer<T>.Default.Equals(field, newValue))
            {
                field = newValue;
                PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    

    Then in your XAML, something like:

    <Button Content="Swap Values" Command="{Binding SwapValues}"/>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="01*"/>
            <ColumnDefinition Width="01*"/>
        </Grid.ColumnDefinitions>
    
        <TextBlock Grid.Column="1" Text="{Binding Text1}" Name="txtBlockABC"/>
        <TextBlock Grid.Column="2" Text="{Binding Text2}"/>
    </Grid>
    

    Where the DataContext for all of the above XAML is an instance of the MyViewModel class.

    Clicking the button labeled "Swap Values" will execute the SwapValuesCommand.Execute() method, which will swap the values. The properties of the UI elements will automatically update.

    I show here the use of an ICommand to execute the swap, but of course you can hook that up to whatever logic you want.

    Caveat: the above was all typed straight into the web browser. I haven't even compiled it, never mind tested it or checked it for typos, etc. It's just for the purpose of illustration. I trust you can use it and other WPF/MVVM examples to understand the basic design concepts used here and adjust the design of your program so that it works the way it's supposed to.


    Of course, if all else fails, I suppose you could go ahead and give that TextBlock a name. Then you can go ahead and access it directly. It's an ill-advised approach, but it'd certainly be a better choice than trying to navigate the visual tree, looking for the TextBlock and hoping you find the right one.