0

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?

Zippy
  • 1,804
  • 5
  • 27
  • 36
PGCafe
  • 3
  • 1
  • What problem you are trying to solve? There could be much more better solution to that instead of storing in in Tag. – Rohit Vats Jan 26 '16 at 15:41
  • Actually, i want to bind the TextBox.Text to my attached property to menu item. And then when click menu item, i can get the value by sender in Click_Event. i also has other menuitem that has no TextBox in it, but also have attached property( just write in xaml ), so i can get the value by user click on any menuitem. – PGCafe Jan 27 '16 at 03:05

3 Answers3

1

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.

Arie
  • 5,251
  • 2
  • 33
  • 54
  • i can't get the TextBox1 in code. so i can't use "mi1.RegisterName("TextBox1", TextBox1);" this to regist TextBox. But thanks for your other information, learn a lot of it. – PGCafe Jan 27 '16 at 03:06
1

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.

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
0

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"/>