【发布时间】:2013-12-13 13:54:36
【问题描述】:
我不太擅长整个 MVVM 设计模式。虽然我觉得这个项目会从中受益,但请记住,这个项目是从 Winforms 转换而来的,当时我只是在学习 WPF。话虽如此,该项目的想法是键盘楔子和键盘挂钩。当程序加载时,主窗口变为不可见,系统托盘上的图标允许该主窗口再次可见。当主窗口可见时,它的中心有一个列表框,允许分配/定义楔形和热键。仅供参考,我将热键称为我从键盘挂钩监控的键。所以假设我正在监控 HotKeys F13-F15,并且我有 2 个键盘楔块。 Item 模板视图很简单。
<UserControl x:Class="Keymon.UserControls.HotkeyConfigurationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Margin="3,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Key}" TextWrapping="Wrap" />
<TextBlock Grid.Column="1" Text="{Binding Path}" HorizontalAlignment="Right" TextWrapping="Wrap" />
</Grid>
</UserControl>
或者简单地将 2 个文本块并排绑定到 Key 和 Path。
我让我的 Hotkeys 和 KeyboardWedges 实现了这个
public interface IMyAdvancedListItem
{
string Key { get; }
string Path { get; }
string Parameters { get; }
}
当我的程序第一次启动时,我会检查我在哪台计算机上,这会给我一个合适的热键和键盘楔形列表。我将它们添加到正确的列表中,然后收集两个值的列表并将它们转换为 IMyAdvancedListItem ... 我最终将其移至 ModelView 以获取 MyAdvancedList
public class MyAdvancedListViewModel
{
public List<Keymon.ValueTypes.IMyAdvancedListItem> Keys
{
get
{
System.Collections.Generic.List<Keymon.ValueTypes.IMyAdvancedListItem> list = new System.Collections.Generic.List<ValueTypes.IMyAdvancedListItem>();
list.AddRange(Globals.MonitoredKeys.Values.Cast<Keymon.ValueTypes.IMyAdvancedListItem>());
list.AddRange(Globals.SerialPortWedges.Values.Cast<Keymon.ValueTypes.IMyAdvancedListItem>());
return list;
}
set
{
}
}
public MyAdvancedListViewModel()
{
}
}
最后,当用户双击列表框项目时,我让它打开正确的配置对话框,然后更新正确的列表。在它更新列表后,我告诉它刷新项目(似乎没有做任何事情)
private void ListBox_MouseDoubleClick(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var keyListBox = sender as ListBox;
var temp = keyListBox.SelectedItem as Keymon.ValueTypes.IMyAdvancedListItem;
var index = keyListBox.SelectedIndex;
if (Globals.SerialPortWedges.ContainsKey(temp.Key))
{
if (temp.Key == "MSR")
ConfigurationHelper.ConfigureWedge(temp.Key);
else
ConfigurationHelper.ConfigureWedgeEx(temp.Key);
}
else
{
ConfigurationHelper.ConfigureHotKey(temp as HotkeyConfiguration);
}
keyListBox.Items.Refresh();
keyListBox.SelectedIndex = index;
}
现在您可能想得很好,只需实现 INotifyCollection.. 就完成了。我什至尝试过 INotifyProperty。我认为最后这一切都可以归结为我只是在猜测我应该做什么而没有 100% 了解我真正在做什么。我的两个列表中的几行重要代码仅供参考。
public class GlobalHotKeys : INotifyCollectionChanged, INotifyPropertyChanged, IEnumerable
{
public GlobalHotKeys()
{
}
public HotkeyConfiguration this[int key]
{
get
{
return MonitoredKeys[key];
}
set
{
MonitoredKeys[key] = value;
NotifyCollectionChanged(NotifyCollectionChangedAction.Replace, value);
NotifyPropertyChanged("Keys");
}
}
private Dictionary<int, HotkeyConfiguration> MonitoredKeys = new Dictionary<int, HotkeyConfiguration>();
public IEnumerable<HotkeyConfiguration> Values { get { return MonitoredKeys.Values; } }
#region Notifications
private void NotifyCollectionChanged(NotifyCollectionChangedAction action, object affectedObject)
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, affectedObject));
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void NotifyPropertyChanged(string property)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
这是我的楔子的代码
public class GlobalWedges : IEnumerable, INotifyCollectionChanged
{
public GlobalWedges()
{
wedges = new Dictionary<string, KeyboardWedgeConfiguration>();
}
public KeyboardWedgeConfiguration this[string key]
{
get
{
if (wedges.ContainsKey(key))
return wedges[key];
else
return null;
}
set
{
wedges[key] = value;
NotifyCollectionChanged(NotifyCollectionChangedAction.Replace, value);
}
}
private Dictionary<string, KeyboardWedgeConfiguration> wedges;
public IEnumerable<KeyboardWedgeConfiguration> Values { get { return wedges.Values; } }
#region Notifications
private void NotifyCollectionChanged(NotifyCollectionChangedAction action, object affectedObject)
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(action, affectedObject));
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endregion
}
我认为您不需要上述列表中项目的代码,所以这里只是类大纲。
public class KeyboardWedgeConfiguration : Keymon.ValueTypes.IMyAdvancedListItem, Keymon.ValueTypes.Saveable, IDisposable
public class HotkeyConfiguration : Keymon.ValueTypes.IMyAdvancedListItem
对不起所有的代码,但有太多总比不够好。哦,我可能忘记了。我必须关闭我的程序而不是重新打开它,然后才能看到对热键列表或键盘楔形所做的更改。我知道他们正在更新,因为如果我更新一个键说打开一个计算器,那么它就会这样做。有什么帮助吗?
编辑
仅此列表的图片。在这个屏幕截图之后,我编辑了 F13 以打开 calc.exe,但列表仍然看起来像这样。
为了显示实际更新,我必须退出我的应用程序,然后重新启动它。这就是我希望程序在刷新时所做的。
【问题讨论】:
-
System.Collections.Generic.List<Keymon.ValueTypes.IMyAdvancedListItem> list = new System.Collections.Generic.List<ValueTypes.IMyAdvancedListItem>();- 人类历史上最好的 C# 代码行。 -
你有没有 gui 的截图?
-
所以它只是你有问题的刷新?
-
如果是这样,我想我们可以参考HighCore的评论。每次在 ViewModel 中调用 getter 时,您都会创建一个新列表。当您在集合已绑定的运行时返回完全不同的/新集合时,它会破坏绑定。相反,本地化集合,并在需要时更新集合。此外,检查输出窗口中的绑定表达式错误。
-
@NETscape 是的。那就是问题所在。我可以更改该列表中的每个项目,但它不会刷新。