Answer the question
In order to leave comments, you need to log in
How to bind the Command Parameter property of the Context Menu to the Name property of the TextBox to which this menu is attached?
Hello.
So I'll start with what I did, and then smoothly move on to what I did not succeed.
I have 6 TextBoxes which have the same ContextMenu.
<TextBox Grid.Column="2" Grid.Row="5" Text="{Binding TextBoxes[110].BoxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.ContextMenu>
<ContextMenu ItemsSource="{Binding Companies}" >
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="ItemsSource" Value="{Binding Workers}"/>
<Setter Property="Header" Value="{Binding CompanyName}"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Command" Value="{Binding MenuCommand}"/>
<Setter Property="CommandParameter" Value="Box_110"/>
</Style>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
ObservableCollection <Company> Companies
within the ViewModel. The collection, in turn, is populated from a small XML file. class Company
{
public string CompanyName { get; set; }
public ObservableCollection<Worker> Workers {get; set;}
public Company(string displayName)
{
CompanyName = displayName;
Workers = new ObservableCollection<Worker>();
}
public class Worker
{
public string Name { get; set; }
public string Signature { get; set; }
public ICommand MenuCommand { get; set; }
public Worker(string name, string signature)
{
MenuCommand = new Command(ContextMenuClick, CanExecuteMethod);
Name = name;
Signature = signature;
}
public void ContextMenuClick(object parameter)
{
switch (parameter)
{
case "Box_115":
MessageBox.Show("Ячейка номер 115");
StampDictionary.TextBoxes["115"].BoxValue = Name;
StampDictionary.TextBoxes["125"].BoxValue = Signature;
break;
case "Box_114":
MessageBox.Show("Ячейка номер 114");
StampDictionary.TextBoxes["114"].BoxValue = Name;
StampDictionary.TextBoxes["124"].BoxValue = Signature;
break;
case "Box_113":
MessageBox.Show("Ячейка номер 113");
StampDictionary.TextBoxes["113"].BoxValue = Name;
StampDictionary.TextBoxes["123"].BoxValue = Signature;
break;
case "Box_112":
MessageBox.Show("Ячейка номер 112");
StampDictionary.TextBoxes["112"].BoxValue = Name;
StampDictionary.TextBoxes["122"].BoxValue = Signature;
break;
case "Box_111":
MessageBox.Show("Ячейка номер 111");
StampDictionary.TextBoxes["111"].BoxValue = Name;
StampDictionary.TextBoxes["121"].BoxValue = Signature;
break;
case "Box_110":
MessageBox.Show("Ячейка номер 110");
StampDictionary.TextBoxes["110"].BoxValue = Name;
StampDictionary.TextBoxes["120"].BoxValue = Signature;
break;
}
}
public bool CanExecuteMethod(object parameter)
{
return true;
}
}
}
<Setter Property="Command" Value="{Binding MenuCommand}"/>
. <Page.Resources>
<ContextMenu x:Key="MyContexMenu" ItemsSource="{Binding Companies}" >
<ContextMenu.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="ItemsSource" Value="{Binding Workers}"/>
<Setter Property="Header" Value="{Binding CompanyName}"/>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Header" Value="{Binding Name}"/>
<Setter Property="Command" Value="{Binding MenuCommand}"/>
<Setter Property="CommandParameter" Value="{Binding Path=Name, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type TextBox}}}"/>
</Style>
</Setter.Value>
</Setter>
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>
...
</Page.Resources>
<TextBox Name="Box_110" Grid.Column="2" Grid.Row="5" Text="{Binding TextBoxes[110].BoxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ContextMenu="{StaticResource MyContexMenu}">
Answer the question
In order to leave comments, you need to log in
You've run into a well-known binding problem in ContextMenu , ToolTip , because those elements are not part of the "visual" tree.
In such cases, two standard solutions are offered - use a PlacementTarget and a proxy object. The first one should fit perfectly.
Before showing the code, I'll note that instead of using the Name property as the key of the TextBox, it's better to use the Tag property .
That is, instead of:
This is not a fundamental change, but in most of the answers for such cases, you will encounter the use of the Tag property.
With this in mind, the binding for the CommandParameter
And a little offtopic:
In your ContextMenuClick handler you use a constant offset equal to 10 and the code is essentially the same for each case. You could shorten the code by first replacing the hint in Tag by removing the "Box_" prefix from there to get something like this:
public void ContextMenuClick(object param)
{
if (int.TryParse(Convert.ToString(param), out int v))
{
StampDictionary.TextBoxes[v.ToString()].BoxValue = Name;
StampDictionary.TextBoxes[(v + 10).ToString()].BoxValue = Signature;
}
}
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question