2010-06-24 186 views
5

我正在尝试设置MenuItem,这将有一个可以选择的页码子菜单。我想将ItemsSource绑定到页码列表(实际上是通过创建列表的转换器将其绑定到PageCount),然后将子菜单中每个MenuItemIsChecked属性绑定到PageIndex。我的问题是第二个绑定,因为它也需要一个转换器,但该转换器需要知道MenuItem代表的页码,但我不知道如何将该信息传递给转换器。这是迄今为止我尝试过的。绑定ItemsSource和IsChecked的MenuItem以获取WPF中的可选项目列表

<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不能被绑定,因为它不是一个DependencyProperty。所以我的问题是如何传递我需要的信息,或者有另一种方式来实现这一点。

注意:我已经试过把MenuItem放在ListBox的内部,就绑定而言效果很好,但是导致子菜单以非标准方式运行。那就是当你打开子菜单时,整个ListBox被当作一个MenuItem

编辑

所以这里就是我已经得到了工作至今。我尝试绑定到隐藏的ListBox,但是当我将MenuItem.ItemsSource绑定到'ListBox.Items'时,我得到了int s的列表,而不是我需要获得IsSelected属性的列表ListBoxItem。所以我最终使用Quartermeister的建议,使用MultiBinding来获取IsChecked属性以模式绑定到PageIndex。为了处理另一个方向,我在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); 
     } 
    } 
} 

回答

3

你想使用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和转换将得到每个孩子结合的结果的数组。在这种情况下,它将是一个两元素数组,其中第一个元素是当前输入,PageIndex,第二个索引是您当前的ConverterParameter,Content。如果你想要双向绑定,ConvertBack将需要返回一个双元素数组,并且你会返回Binding.DoNothing作为第二个参数,这样它就不会尝试更新内容。

+0

这并不适用于两项工作因为我需要知道两个方向的Content值,并且只传递给Convert而不是ConvertBack。 – juharr 2010-06-25 13:03:29

+0

即使这个想法在两个方向都不起作用,它让我在那里一半,所以,你赢了。 – juharr 2010-06-25 21:27:22

3

听起来就像你正试图建立动态菜单,控制每个菜单项的选中状态。
我扩展了一些我编写的代码,用MVVM模式在WPF中构建动态菜单并添加了检查逻辑。

这里是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; } 
    } 
+0

这个例子的问题是菜单项的数量是静态的。在我的应用程序中,“CurrentImage”可以更改,然后我需要更新要匹配的菜单项的数量。此外,这看起来就像代码中的事件处理创建菜单项,然后处理每个菜单项“Checked”事件,我希望有一个XAML解决方案。 – juharr 2010-06-25 16:13:01

+0

您可以扩展我的解决方案以在CurrentImage更改时重新加载命令列表,但我同意这是很多(简单)代码。如果您发布CurrentImage的代码,可能会帮助我和其他人更好地了解您的问题。 – Zamboni 2010-06-25 16:37:11

相关问题