PGCafe
PGCafe

Reputation: 3

Binding ElementName in menuitem's header

i try to bind the TextBox's text in MenuItem's header to MenuItem's Tag property. but it won't work correct, always get Null in Tag property.

the code is like below...

        <Button x:Name="Button1" Content="Test" HorizontalAlignment="Left" Width="182" Height="34" VerticalAlignment="Top" Margin="160,113,0,0">
        <Button.ContextMenu>
            <ContextMenu PlacementTarget="{Binding ElementName=Button1}" Placement="Bottom">
                <MenuItem Tag="{Binding ElementName=TextBox1, Path=Text}" Click="MessageBox_ShowTag">
                    <MenuItem.Header>
                        <Grid Height="25" MinWidth="153">
                            <Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
                            <TextBox x:Name="TextBox1" VerticalContentAlignment="Center" Margin="91,0,0,0"/>
                        </Grid>
                    </MenuItem.Header>
                </MenuItem>
            </ContextMenu>
        </Button.ContextMenu>
    </Button>

When click on menuitem, call the MessageBox to show the tag in MenuItem ( MessageBox.Show( ( sender as MenuItem ).Tag?.ToString() ); )

MessageBox has show but content is always empty.

Result: Result

how can i bind to textbox?

Upvotes: 0

Views: 269

Answers (3)

Rohit Vats
Rohit Vats

Reputation: 81233

Like mentioned in the comment also, there could be better solution to actual problem you are trying to solve.

But anyhow if you want solution for your specific problem it can be solved by using x:Reference in place of ElementName like this:

<MenuItem Tag="{Binding Source={x:Reference TextBox1}, Path=Text}"/>

ElementName is not working because VisualTree is different. In case interested read further here - ElementName v/s x:Reference.

Upvotes: 1

Arie
Arie

Reputation: 5373

I don't know why you have to bind it like that. An alternative would be to bind to a property (here: MyText) that implements INotifyPropertyChanged, and then pass the DataContext to the menu like this:

 <Button x:Name="Button1" Content="Test" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <Button.ContextMenu>
                <ContextMenu Placement="Bottom"  DataContext="{Binding Path=PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                    <MenuItem>
                        <MenuItem.Header>
                            <Grid Height="25" MinWidth="153">
                                <Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
                                <TextBox Name="TextBox1" Text="{Binding Path=MyText}"
                                         VerticalContentAlignment="Center" Margin="91,0,0,0"/>
                            </Grid>
                        </MenuItem.Header>
                    </MenuItem>
                </ContextMenu>
            </Button.ContextMenu>
        </Button>

And then not relay on Click event to get the TextBox value at all.

If you want to know why your binding doesn't work, its because your MenuItem can't find an object named TextBox1 in its Namescope. If you must (namescopes are a bit tricky), you may make it work by creating a new Namescope for your MenuItem and registering the name for the TextBox:

NameScope.SetNameScope(mi1, new NameScope());
mi1.RegisterName("TextBox1", TextBox1);

where mi1 is the name of your MenuItem, then your binding will work:

<Button x:Name="Button1" Content="Test" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
    <Button.ContextMenu>
        <ContextMenu Placement="Bottom">
            <MenuItem Tag="{Binding ElementName=TextBox1, Path=Text}" Click="MessageBox_ShowTag" Name="mi1">
                <MenuItem.Header>
                    <Grid Height="25" MinWidth="153">
                        <Label Content="Label1" Width="86" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
                        <TextBox Name="TextBox1" VerticalContentAlignment="Center" Margin="91,0,0,0"/>
                    </Grid>
                </MenuItem.Header>
            </MenuItem>
        </ContextMenu>
    </Button.ContextMenu>
</Button>

Also, avoid x:Name whenever you can. It can cause some nasty memory leaks. Use Name instead.

Upvotes: 1

Particle of Wisdom
Particle of Wisdom

Reputation: 1

Try binding via RelativeSource:

<TextBox x:Name="TextBox1" Text="{Binding Path=Tag, RelativeSource={RelativeSource AncestorType={x:Type MenuItem}}}" VerticalContentAlignment="Center" Margin="91,0,0,0"/>

Upvotes: 0

Related Questions