这个问题的变体似乎很常见,但我还没有找到适合我的解决方案。我正在尝试使用 Observable 集合在 Button.ContextMenu 中放置一个下拉菜单,并认为我在正确的轨道上,缺少一个:我还没有能够获得所选项目的索引,虽然我可以在调试器中看到我的收藏,我开始怀疑这些项目是否真的被找到了,我会边走边解释。首先,XAML……你可以看到我有一个按钮内容的绑定,这个想法是在一个菜单项被选中后,我的代码将更新该属性。如果我可以获得正在收集的集合的索引,它可以:
<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 下看到了一个合法的项目标签.CurrentPosition 是 0 - 起初看起来很有希望,希望我可以将其用作索引,直到我意识到我正在查看最后一项,所以它一定是没有意义的。之后,第二次以及所有后续按下按钮,items.CurrentItem 为空,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;
}
认为这就是一切。任何帮助是极大的赞赏。如果这看起来很熟悉,那就是。我越过了第一道障碍,撞上了这堵砖墙。