我是WPF的新手,需要学习更多有关MVVM的知识。我的代码并没有专门设计成MVVM模式,但我已经将一个类指定为GUI的接口和控制器,而模型代码则位于另一组类中。我在网上寻找示例和与我相似的问题,虽然有很多,但是经过三天的努力我依然需要帮助。
我需要一个简单的下拉菜单,其中的项可以动态更新(这是一个与USB设备通信的应用程序,因此应显示可用设备的数量以及它们的设备ID和序列号),并且当前选择的项应该显示在按钮上(或者无论哪种下拉菜单实现方式)。在这个示例中,我只创建了一个静态列表,但是在完整的应用程序中将动态更新同样的列表。
到目前为止,我的代码看起来是正确的:我让当前选定的设备ID字符串显示在按钮上,并在按下按钮时获取所有可用设备的列表(当前选定的设备出现在列表中不会对我造成太大的困扰)。然而,我无法钩入任何事件,当项被选择时,因此无法更新按钮中的项,或者执行其他任何操作。
以下是我的XAML。请注意,这是粗略地混合在一起的,其中有一些毫无意义的东西,比如“IsActive”用于“IsChecked”属性,这来自示例。最大的问题是据我所知,ContextMenu.Resources中的任何Setter属性似乎都没有起作用...尝试更改字体大小但无济于事。当然,真正的大问题是“MyCommand”绑定不起作用,该方法从未被调用。
<Label Content="Device Selected:" HorizontalAlignment="Left" Margin="25,22,0,0" VerticalAlignment="Top" Width="124" FontWeight="Bold" FontSize="14" Height="25"/>
<Button x:Name="DeviceSelMenuButton" Content="{Binding DeviceID_and_SN, Mode=TwoWay}" HorizontalAlignment="Left" Height="28" Margin="25,52,0,0" VerticalAlignment="Top" Width="187" FontSize="14" Click="DeviceSelMenuButton_Click">
<Button.ContextMenu>
<ContextMenu ItemsSource="{Binding DeviceID_SN_Collection, Mode=TwoWay}">
<ContextMenu.Resources>
<Style x:Key="SelectDeviceStyle" TargetType="MenuItem">
<Setter Property="Command" Value="{Binding MyCommand}"/>
<Setter Property="CommandTarget" Value="{Binding RelativeSource Self}"/>
<Setter Property="IsChecked" Value="{Binding IsActive}"/>
<Setter Property="IsCheckable" Value="True"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</ContextMenu.Resources>
</ContextMenu>
</Button.ContextMenu>
</Button>
以下是MainWindow.xaml.cs中的代码:
public partial class MainWindow : Window
{
CustomDeviceGUI _customDeviceGui = new CustomDeviceGUI();
public MainWindow()
{
InitializeComponent();
this.DataContext = _customDeviceGui;
}
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;
}
private void SomeMethod(object sender, DataTransferEventArgs e)
{
// TODO Somehow get the index of the selected menu item (collection index, 0-based)
// int selIndex = (sender as Button).ContextMenu.Items.IndexOf ??
_customDeviceGui.UpdateDeviceID("RelayPro id updated");
}
}
以及GUI代码:
class CustomDeviceGUI : INotifyPropertyChanged
{
// Declare the event
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private string _deviceDisplayString;
private ICommand _updateMenu;
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(ControllerDeviceList[0]);
}
#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 (_updateMenu == null)
_updateMenu = new MyGuiCommand();
return _updateMenu;
}
}
#endregion
#region Public Methods
public void UpdateDeviceID(string deviceID)
{
this._deviceDisplayString = deviceID;
RaisePropertyChangeEvent("DeviceID_and_SN");
RaisePropertyChangeEvent("DeviceID_SN_Collection");
}
#endregion
protected void RaisePropertyChangeEvent(string name)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
try
{
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
catch (Exception e)
{
// ... TODO Remove this catchall or find specific exceptions
}
}
public class MyGuiCommand : ICommand
{
public void Execute(object parameter)
{
// Debug.WriteLine("Hello, world");
int hmm = 3;
}
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged // was ;
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
} // class CustomDeviceGUI