Я пытаюсь установить a MenuItem
это будет иметь подменю номеров страниц, которые могут быть выбраны. Я хочу связать ItemsSource
к списку номеров страниц (на самом деле к PageCount с преобразователем, создающим список) и затем, связывают IsChecked
свойство каждого MenuItem
в подменю к PageIndex. Моя проблема со второй привязкой, поскольку она также требует преобразователя, но тот преобразователь должен знать номер страницы что MenuItem
представляет, но я не могу выяснить, как передать ту информацию преобразователю. Вот то, что я попробовал до сих пор.
<MenuItem Header="_Goto Page"
ItemsSource="{Binding
Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="True"/>
<Setter Property="IsChecked"
Value="{Binding
ElementName=MainWindow,
Path=CurrentImage.PageIndex,
Mode=TwoWay,
Converter={StaticResource pageNumChecked},
ConverterParameter={Binding
RelativeSource={RelativeSource Self},
Path=Content}}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
Конечно, проблема состоит в том что ConverterParameter
не может быть связан, поскольку это не a DependencyProperty
. Таким образом, мой вопрос состоит в том, как я могу передать в информации, в которой я нуждаюсь или есть ли другой способ сделать это.
Примечание: Я уже попытался поместить MenuItem
s в a ListBox
который работавший действительно хорошо насколько привязка затронута, но заставила подменю вести себя нестандартным способом. Это - при открытии подменю все ListBox
рассматривался как один MenuItem
.
Править
Таким образом, вот то, что я взялся за работу до сих пор. Я пытался связать со скрытым ListBox
но когда я связал MenuItem.ItemsSource
к 'ListBox. Объекты я получил список int
s вместо списка ListBoxItem
s, который я должен был получить IsSelected
свойство. Таким образом, я закончил тем, что использовал предложение Quartermeister использования MultiBinding для получения IsChecked
свойство для привязки с PageIndex
в OneWay
режим. Для обработки другого направления, я использовал обработчик событий на Click
событие. Стоит отметить, что сначала я имел IsCheckable
набор к true
и работал с Checked
событие, но это закончилось, некоторые нечетные поведения.
<MenuItem x:Name="GotoPageMenuItem" Header="_Goto Page"
ItemsSource="{Binding Path=CurrentImage.PageCount,
Converter={StaticResource countToList}}">
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="IsCheckable"
Value="False"/>
<EventSetter Event="Click"
Handler="GotoPageMenuItem_Click"/>
<Setter Property="IsChecked">
<Setter.Value>
<MultiBinding Converter="{StaticResource pageNumChecked}"
Mode="OneWay">
<Binding RelativeSource="{RelativeSource FindAncestor,
AncestorType={x:Type Window}}"
Path="CurrentImage.PageIndex"
Mode="OneWay"/>
<Binding RelativeSource="{RelativeSource Self}"
Path="Header"
Mode="OneWay"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
И вот GotoPageMenuItem_Click
код
private void GotoPageMenuItem_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
if (item != null)
{
//If the item is already checked then we don't need to do anything
if (!item.IsChecked)
{
var pageNum = (int)item.Header;
CurrentImage.PageIndex = (pageNum - 1);
}
}
}
Можете ли вы сделать то, что хотите, используя MultiBinding?
<Setter Property="IsChecked">
<Setter.Value>
<MultiBinding Converter="{StaticResource pageNumChecked}">
<Binding ElementName="MainWindow" Path="CurrentImage.PageIndex" Mode="TwoWay"/>
<Binding RelativeSource="{RelativeSource Self}" Path="Content"/>
</MultiBinding>
</Setter.Value>
</Setter>
Пусть ваш конвертер pageNumChecked
реализует IMultiValueConverter вместо IValueConverter, и Convert получит массив с результатом каждого дочернего связывания. В данном случае это будет двухэлементный массив, где первым элементом будет ваш текущий вход, PageIndex, а вторым индексом - текущий параметр конвертера, Content. Если вы хотите двустороннее связывание, ConvertBack должен вернуть двухэлементный массив, а для второго параметра вы вернете Binding.DoNothing
, чтобы он не пытался обновить Content.
Похоже, вы пытаетесь создать динамическое меню, которое контролирует отмеченное состояние каждого пункта меню.
Я расширил написанный мной код для создания динамических меню в WPF с шаблоном MVVM и добавил проверенную логику.
Вот XAML:
<Menu DockPanel.Dock="Top">
<MenuItem ItemsSource="{Binding Commands}"
Header="_Item Container Style">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="IsChecked" Value="{Binding Path=Checked}"/>
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="Command" Value="{Binding Path=Command}" />
<Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</Menu>
Вот модель представления:
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
GoCommand = new DelegateCommand<object>(OnGoCommand, CanGoCommand);
LoadCommands();
}
private List<MyCommand> _commands = new List<MyCommand>();
public List<MyCommand> Commands
{
get { return _commands; }
}
private void LoadCommands()
{
MyCommand c1 = new MyCommand { Command = GoCommand, Parameter = "1", Text = "Menu1", Checked = true};
MyCommand c2 = new MyCommand { Command = GoCommand, Parameter = "2", Text = "Menu2", Checked = true };
MyCommand c3 = new MyCommand { Command = GoCommand, Parameter = "3", Text = "Menu3", Checked = false };
MyCommand c4 = new MyCommand { Command = GoCommand, Parameter = "4", Text = "Menu4", Checked = true };
MyCommand c5 = new MyCommand { Command = GoCommand, Parameter = "5", Text = "Menu5", Checked = false };
_commands.Add(c1);
_commands.Add(c2);
_commands.Add(c3);
_commands.Add(c4);
_commands.Add(c5);
}
public ICommand GoCommand { get; private set; }
private void OnGoCommand(object obj)
{
}
private bool CanGoCommand(object obj)
{
return true;
}
}
Вот класс, который содержит команды:
public class MyCommand
{
public ICommand Command { get; set; }
public string Text { get; set; }
public string Parameter { get; set; }
public Boolean Checked { get; set; }
}