我正在制作一个小型 MVVM 应用程序。它应该采用一个完整的类Func<string>
,并显示一个按钮列表,每个按钮执行一个包含 a 的命令Func<string>
,并在另一个列表中显示它们的返回值。
该程序起初运行良好,但在按下随机数量的按钮后,它只会停止执行命令。UI 仍然是响应式的。就好像束缚断了一样。
类太多了,所以我将整个项目附在以下链接中:
http://www.megafileupload.com/en/file/403770/GenericTester-zip.html
相关代码:
namespace AdapterTester.ViewModel
{
public class MainViewModel : ViewModelBase
{
public ObservableCollection<ViewableRelayCommand> CommandsList { get; set; }
public ObservableCollection<string> Log { get; set; }
/// <summary>
/// Initializes a new instance of the MainViewModel class.
/// </summary>
public MainViewModel()
{
CommandsList = new ObservableCollection<ViewableRelayCommand>();
Log = new ObservableCollection<string>();
MapCommands();
}
/// <summary>
/// adds a ViewableRelayCommand to the CommandsList
/// </summary>
public void Add(Func<string> iCommand, string CommandName, Func<bool> CanExecute = null)
{
CommandsList.Add(new ViewableRelayCommand()
{
Command = new RelayCommand(() => { Log.Insert(0, "-------------\n" + CommandName + "\n" + (iCommand.Invoke())); }),
CommandName = CommandName
});
}
/// <summary>
/// For Each Func<string> in TestFunctions create a ViewableRelayCommand
/// </summary>
private void MapCommands()
{
var target = new TestFunctions();
var methods = target.GetType().GetMethods().Where(m => m.DeclaringType == typeof(TestFunctions));
foreach (var method in methods)
{
if( (method.ReturnType == typeof(string)) && (method.GetParameters().Length ==0))
{
Func<string> func = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), target, method);
Add(func, method.Name);
}
}
}
}
public class ViewableRelayCommand : ViewModelBase
{
public RelayCommand Command { get; set; }
/// <summary>
/// The <see cref="CommandName" /> property's name.
/// </summary>
public const string CommandNamePropertyName = "CommandName";
private string _CommandName = "Hello";
/// <summary>
/// Sets and gets the CommandName property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public string CommandName
{
get
{
return _CommandName;
}
set
{
if (_CommandName == value)
{
return;
}
RaisePropertyChanging(CommandNamePropertyName);
_CommandName = value;
RaisePropertyChanged(CommandNamePropertyName);
}
}
}
}
XAML:
<Window x:Class="AdapterTester.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
Width="500"
Height="300"
Title="MVVM Light Application"
DataContext="{Binding Main, Source={StaticResource Locator}}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
<DataTemplate x:Key="myButtonTemplate">
<Button Content="{Binding Path=CommandName}" Command="{Binding Path=Command}" Margin="3"></Button>
</DataTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListBox Name="CommandsListBox" Grid.Column="0"
ItemsSource="{Binding CommandsList}"
ItemTemplate="{StaticResource myButtonTemplate}">
</ListBox>
<ListBox Name="LogListBox" Grid.Column="1"
ItemsSource="{Binding Log}"
</ListBox>
</Grid>
</Window>
更新:
答案是改变:
Command = new RelayCommand(() => { Log.Insert(0, "-------------\n" + CommandName + "\n" + (iCommand.Invoke())); }),
像这样:
List<Action> actions = new List<Action>();
public void Add(Func<string> iCommand, string CommandName, Func<bool> CanExecute = null)
{
Action act = () => { Log.Insert(0, "-------------\n" + CommandName + "\n" + (iCommand.Invoke())); };
actions.Add(act);
CommandsList.Add(new ViewableRelayCommand()
{
Command = new RelayCommand(act)
,
CommandName = CommandName
});
}
因为添加到中继命令的操作没有植根。
更新更改为我自己的中继命令有所帮助。虽然生根 Funcs 没有。