2010-06-24 22 views
5

Estoy intentando configurar un MenuItem que tendrá un submenú de números de página que se pueden seleccionar. Quiero vincular ItemsSource a una lista de números de página (en realidad, a PageCount con un convertidor que crea la lista) y luego vincular la propiedad IsChecked de cada MenuItem en el submenú al PageIndex. Mi problema es con el segundo enlace ya que también requiere un convertidor, pero ese convertidor necesita saber el número de página que representa el MenuItem, pero no entiendo cómo pasar esa información al convertidor. Esto es lo que he intentado hasta ahora.Vinculando ItemsSource y IsChecked de un MenuItem para obtener una lista de elementos seleccionables en 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> 

Por supuesto, el problema es que el ConverterParameter no puede estar obligado, ya que no es un DependencyProperty. Entonces mi pregunta es cómo puedo pasar la información que necesito o si hay otra manera de hacerlo.

Nota: Ya he intentado poner el MenuItem s dentro de un ListBox que funcionó muy bien en lo que respecta a las vinculaciones, pero hizo que el submenú se comportara de una manera no estándar. Es entonces cuando abrió el submenú, el ListBox completo se trató como uno MenuItem.

Editar

Así que aquí es lo que he llegado a trabajar hasta el momento. Intenté vincular a un ListBox oculto pero cuando até el MenuItem.ItemsSource al 'ListBox.Items' obtuve la lista de int s en lugar de una lista de ListBoxItem que necesitaba para obtener la propiedad IsSelected. Así que terminé usando la sugerencia de Quartermeister de usar MultiBinding para obtener la propiedad IsChecked para enlazar al PageIndex en el modo OneWay. Para manejar la otra dirección, utilicé un controlador de eventos en el evento Click. Vale la pena señalar que al principio tenía IsCheckable establecido en true y estaba trabajando con el evento Checked, pero que dio como resultado algunos comportamientos extraños.

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

Y aquí está el código

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); 
     } 
    } 
} 

Respuesta

3

GotoPageMenuItem_Click Se puede hacer lo que quiera usar un 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> 

El convertidor de implementar pageNumCheckedIMultiValueConverter en lugar de IValueConverter y convertir obtendrá una matriz con el resultado de la unión de cada niño. En este caso, sería una matriz de dos elementos donde el primer elemento es su entrada actual, PageIndex, y el segundo índice es su parámetro convertidor actual, contenido. Si desea vinculación bidireccional, ConvertBack deberá devolver una matriz de dos elementos, y devolverá Binding.DoNothing para el segundo parámetro, de modo que no intente actualizar el Contenido.

+0

esto no funciona para dos el enlace de ruta porque necesito saber el valor de 'Contenido' para ambas direcciones y solo se pasa al 'Convert' y no al' ConvertBack'. – juharr

+0

Aunque esta idea no funcionó en ambas direcciones, me llevó a la mitad así que ganas. – juharr

3

Parece que está intentando crear menús dinámicos que controlan el estado comprobado de cada elemento del menú.
Amplié un código que escribí para crear menús dinámicos en WPF con el patrón MVVM y agregué la lógica comprobada.

Aquí es el 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> 

Aquí es el Modelo Vista:

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; 
    } 
} 

Aquí es la clase que contiene los comandos:

public class MyCommand 
    { 
    public ICommand Command { get; set; } 
    public string Text { get; set; } 
    public string Parameter { get; set; } 
    public Boolean Checked { get; set; } 
    } 
+0

El problema con este ejemplo es que la cantidad de elementos del menú es estática. En mi aplicación, 'CurrentImage' puede cambiar y luego tendría que actualizar la cantidad de elementos del menú para que coincidan. También esto parece tanto código como simplemente crear los elementos del menú en el código con el manejo del evento y luego manejar cada elemento del menú 'Comprobado' y esperaba una solución XAML. – juharr

+0

Puede ampliar mi solución para volver a cargar la lista de comandos cuando la imagen actual cambie, pero acepto que es una gran cantidad de código (simple). Si publica el código de CurrentImage que podría ayudarnos a mí y a otros a tener una mejor idea de su pregunta. – Zamboni

Cuestiones relacionadas