更新
改为我自己的接力命令有帮助.
虽然生根Funcs没有
大家好,我正在制作一个小型MVVM应用程序.这应该是一个完整的课程
FUNC<串GT;并显示每个执行包含Func< string>的命令的按钮列表.并在另一个列表中显示其返回值.
该程序首先工作正常,但在按下一个按钮后,它只是停止执行命令.用户界面仍然具有响应性.好像绑定破了.
有太多的类,所以我将整个项目附加在以下链接中
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
});
}
因为添加到relay命令的操作没有root
最佳答案 它是否使用MVVMLight的RelayCommand?
如果是这样,您可能会遇到GC问题. RelayCommand在内部对其回调使用WeakReference.
如果您传入的是一个未在其他地方生根的匿名函数,那么当GC运行时它可能会被清除.
大多数情况下这不是问题,因为func是对VM的回调,VM本身植根于DataContext,ViewModelLocator或其他地方.如果你创建的Func不是root,那可能是个问题.
根这些Func的一种方法是使用List< Func< string>>在ViewModel中,并在创建RelayCommands的同时将它们添加到列表中.