2013-11-09 53 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