Здравствуйте.
Начну значит я с того, что у меня получилось, а потом плавно перейдем к тому, что у меня не получилось.
У меня есть 6 TextBox, которые имеют одинаковое 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>
Обратите внимание на свойство CommandParameter, это единственное свойство, которое уникально у каждого ContextMenu.
Само меню заполняется из
ObservableCollection <Company> Companies
, расположенном в ViewModel. Коллекция в свою очередь заполняется из небольшого XML файла.
Класс Company имеет поле, содержащее имя компании и список рабочих, которые в свою очередь имеют имя и подпись.
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;
}
}
}
Вложенный класс Worker имеет MenuCommand привязанную к ContextMenu
<Setter Property="Command" Value="{Binding MenuCommand}"/>
.
С помощью оператора switch(parameter), я проверяю CommandParameter ContextMenu у TextBox, в котором оно вызвано и выполняю вставку Name и Signature в Dictionary, который через Binding связан с моим TextBox. (Такая махинация со словарем мне нужна для дальнейших действий со вставкой значений в штамп чертежа через Kompas.Api)
Все работает прекрасно.
Однако вот проблема меня задела. Код ContextMenu повторяется целых 6 раз(а могло быть и больше, например), а изменяется только один CommandParameter и я твердо решил постараться изменить такое положение вещей.
ContextMenu я положил в Resources
<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>
Обратите внимание на строку CommandParameter. Я (даже не знаю как я смог такое отрыть) здесь пытаюсь привязать CommandParameter к свойству Name у TextBox, которому принадлежит ContextMenu.
TextBox в свою очередь выглядит так
<TextBox Name="Box_110" Grid.Column="2" Grid.Row="5" Text="{Binding TextBoxes[110].BoxValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ContextMenu="{StaticResource MyContexMenu}">
Здесь мы видим, что через StaticResources я подтягиваю ContextMenu и видим Name у TextBox, которое является аналогом того, что раньше было у CommandParameter.
И так, теперь посмотрим скрины, метод работает, но не совсем так как хотелось бы.
И вроде бы все хорошо да? Прямо как и раньше.
Однако если я постараюсь в другую ячейку выбрать имя из, например Люди, то он посчитает, что ContextMenu вызвано у ячейки Box_110, в котором оно было вызвано в первый раз.
Также работает и со всеми остальными. Вызвав в ячейке имя из любого меню, это меню привязывается только к этой ячейке. Остальные же меню, пока не были вызваны, работают адекватно также до первого их вызова.
Так как же мне решить эту проблему?
Опыта программирования на c# у меня около двух с половиной месяцев, это мой первый большой проект и, наверное, мою реализацию больше можно назвать "творчеством". Однако я точно хочу заставить работать ContextMenu через StaticRecources, потому что мне кажется, что мой алгоритм...нормальный)
Приму к сведению любые махи рукой в сторону, куда копать.
Спасибо.