2013-11-09 27 views
0

这个问题的变化似乎是相当普遍的,但我还没有找到一个适合我的解决方案。我试图在Button.ContextMenu中使用Observable集合放置下拉菜单,并且认为我处于正确的轨道上,缺少一件:我还没有能够获得所选项目的索引,尽管我可以在调试器中看到我的集合,我开始怀疑这些项目是否真的被找到,并会在我去的时候解释。首先,XAML ...你可以看到我有一个Button内容的绑定,并且这个想法是在菜单项被选中后,我的代码将会更新这个属性。它可以,如果我能得到正采集收集的指标:正确绑定下拉菜单从ObservableCollection并获得其索引

<Button x:Name="DeviceSelMenuButton" Content="{Binding DeviceID_and_SN, Mode=TwoWay}" HorizontalAlignment="Left" Height="28" Margin="25,103,0,0" VerticalAlignment="Top" Width="187" FontSize="14" Click="DeviceSelMenuButton_Click"> 
     <Button.ContextMenu> 
      <ContextMenu ItemsSource="{Binding DeviceID_SN_Collection, Mode=TwoWay}"> 
       <ContextMenu.ItemContainerStyle> 
        <Style TargetType="MenuItem"> 
         <Setter Property="IsCheckable" Value="true"/> 
         <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}, Path=DataContext.MyCommand}"/> 
         <Setter Property="CommandParameter" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ContextMenu}}}"/> 
        </Style> 
       </ContextMenu.ItemContainerStyle> 
      </ContextMenu> 
     </Button.ContextMenu> 
    </Button> 

正如你可以想像,我已经尝试了许多变化对于CommandParameter绑定,但是这一个我至少可以看到一些我的ICommand方法中的东西。麻烦我的事情是,在第一次按下按钮(并且在输出窗口中没有关于绑定的错误)时,在ContextMenu cm的Items属性下,我看到items.CurrentItem下的合法项目标签和item当前位置是0--最初看起来很有希望,希望我可以用它作为索引,直到我意识到我正在查看最后一个项目,所以它一定是没有意义的。之后,第二次以及随后按下按钮时,items.CurrentItem为null,items.Current位置为0xffffffff。粘贴在代码中的相关片段,先从类定义集合,ICommand的,等:

class CustomDeviceGUI : INotifyPropertyChanged 
{ 
    // Declare the event 
    public event PropertyChangedEventHandler PropertyChanged = delegate { }; 
    private string _deviceDisplayString; 
    private ICommand UpdateMenuICommand; 
    List<string> ControllerDeviceList = new List<string>(); 

    private System.Collections.ObjectModel.ObservableCollection<string> _DeviceID_SN_Collection = new System.Collections.ObjectModel.ObservableCollection<string>(); 

    // CTOR 
    public CustomDeviceGUI() 
    { 
     ControllerDeviceList.Add("CustomDevice Device 1"); 
     ControllerDeviceList.Add("CustomDevice Device 2"); 
     ControllerDeviceList.Add("CustomDevice Device 3"); 
     ControllerDeviceList.Add("CustomDevice Device 6"); 
     UpdateDeviceID(3); // TODO Get from GUI!!! 
    } 

    #region CustomDeviceGUI Properties 

    public System.Collections.ObjectModel.ObservableCollection<string> DeviceID_SN_Collection 
    { 
     get 
     { 
      _DeviceID_SN_Collection.Clear(); 
      foreach (string str in ControllerDeviceList) 
      { 
       _DeviceID_SN_Collection.Add(str); 
      } 
      return _DeviceID_SN_Collection; 
     } 
     private set 
     { 
      _DeviceID_SN_Collection = value; 
     } 
    } 

    public string DeviceID_and_SN 
    { 
     get 
     { 
      return _deviceDisplayString; 
     } 
     private set 
     { 
      _deviceDisplayString = value; 
     } 
    } 

    public ICommand MyCommand 
    { 
     get 
     { 
      if (UpdateMenuICommand == null) 
       UpdateMenuICommand = new MyGuiCommand(); 

      return UpdateMenuICommand; 
     } 
     set 
     { 
      UpdateMenuICommand = value; 
      RaisePropertyChangeEvent("MyCommand"); // ???? 
     } 
    } 

    public void UpdateDeviceID(int deviceID) 
    { 
     this._deviceDisplayString = ControllerDeviceList[deviceID]; 
     RaisePropertyChangeEvent("DeviceID_and_SN"); 
     RaisePropertyChangeEvent("DeviceID_SN_Collection");  
    } 

    public class MyGuiCommand : ICommand 
    { 
     // Two events are kicked off when the command is executed 
     public static event UpdateDeviceSelectedEventHandler UpdateDeviceSelectedEvent; 

     // defining signature for any event handlers for the events we create here 
     public delegate void UpdateDeviceSelectedEventHandler(int deviceIndex); 

     public void Execute(object parameter) 
     { 
      ContextMenu cm = (ContextMenu)parameter; 
      var itemSource = cm.ItemsSource; 
      var itemBG = cm.ItemBindingGroup; 
      var items = cm.Items; 

      UpdateDeviceSelectedEvent(1); // TODO parameter with index from GUI  
     } 

     public bool CanExecute(object parameter) 
     { 
      return true; 
     } 
     public event EventHandler CanExecuteChanged // was ; 
     { 
      add { CommandManager.RequerySuggested += value; } 
      remove { CommandManager.RequerySuggested -= value; } 
     } 
    } 
} // class CustomDeviceGUI 

终于从MainWindow.xaml.cs相关的代码,而不是很多发生在这里:

// register for the event from the ICommand.Execute 
    WpfBindingAttempts.CustomDeviceGUI.MyGuiCommand.UpdateDeviceSelectedEvent += new WpfBindingAttempts.CustomDeviceGUI.MyGuiCommand.UpdateDeviceSelectedEventHandler(UpdateDeviceSelectedAfterSwitch); 

    // Handles event that occurs when a different device is selected 
    // via the dropdown menu -- sets the active device, and updates its ID/SN 
    void UpdateDeviceSelectedAfterSwitch(int deviceIndex) 
    { 
     _customDeviceGui.UpdateDeviceID(deviceIndex); 
    } 

代码背后按钮:

private void DeviceSelMenuButton_Click(object sender, RoutedEventArgs e) 
    { 
     // " (sender as Button)" is PlacementTarget 
     (sender as Button).ContextMenu.IsEnabled = true; 
     (sender as Button).ContextMenu.PlacementTarget = (sender as Button); 
     (sender as Button).ContextMenu.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom; 
     (sender as Button).ContextMenu.IsOpen = true; 
    } 

认为这一切。任何帮助是极大的赞赏。如果这看起来很熟悉,那就是。我克服了第一个障碍,撞上了这堵砖墙。

回答

1

我不认为有任何直接的方式来返回ContextMenu内的项目的选定索引。我不相信CurrentItem属性持有与选择哪个项目有关的任何内容。我不确定这个属性究竟做了什么(它可能是框架内部使用的东西),但我会建议你忽略它。

而不是使上下文菜单为CommandParameter,使您的集合中的项目CommandParameter s。要做到这一点,CommandParameter二传手更改为以下:

<Setter Property="CommandParameter" Value="{Binding}" /> 

然后,所有设备的列表传递给您的MyGuiCommand,在例如构造函数的参数。最后,在您的Execute方法中,在设备列表中搜索以找到所选设备,该设备将位于parameter中。

+0

谢谢你,谢谢你,指出明显的我! – Stephen