【问题标题】:RelayCommand stops working after a whileRelayCommand 在一段时间后停止工作
【发布时间】:2014-09-16 11:59:29
【问题描述】:

我在使用 GalaSoft 的 RelayCommand 时遇到了一些问题。

我有一个 NextCommand 属性有效,但只有几次。

之后,它完全停止工作。

您可以通过示例项目进行尝试:

http://s000.tinyupload.com/?file_id=65828891881629261404

行为如下:

  1. 下一个命令
    1. 弹出所有项目直到活动索引
    2. 如果剩余少于 50 个项目,则推送 1 个新项目
    3. 将新项目标记为活动
  2. BackCommand
    1. 将活动索引向后移动 1 个位置

复制步骤:

  1. “+”(OemPlus) 键已绑定到 NextCommand
  2. '-' (OemMinus) 键已绑定到 BackCommand
  3. 按住“+”键直到列表停止增长(限制为 50 项)
  4. 按住“-”键直到列表中的第一项处于活动状态
  5. 重复

(复制错误)所需的重复次数不一致。

有时我会在 4 次重复后得到它;其他时间到 9 点。

// Items Collection
public class ItemCollection : ViewModelBase
{
    // List of Items
    private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
    public ObservableCollection<Item> Items
    {
        get { return _items; }
    }

    // Constructor
    public ItemCollection()
    {
        BackCommand = new RelayCommand(
                () =>
                {
                    // Go to previous page
                    var index = Items.IndexOf(ActiveItem);
                    if (index > 0)
                    {
                        ActiveItem = Items[index - 1];
                    }
                },
                () => ActiveItem != null && Items.IndexOf(ActiveItem) > 0);
    }

    // Back command
    public RelayCommand BackCommand { get; set; }

    // Next command
    public RelayCommand NextCommand { get; set; }

    // The currently-active item
    private Item _activeItem;
    public Item ActiveItem
    {
        get { return _activeItem; }
        set
        {
            Set(() => ActiveItem, ref _activeItem, value);
        }
    }
}

// Item
public class Item : ViewModelBase
{
    public string Title { get; set; }
}

当我进入 RelayCommand 的代码时,执行操作的 isAlive 标志为假。但我似乎无法弄清楚这是怎么发生的。

【问题讨论】:

  • +1 为您解释问题的精美动画 Gif。
  • 我没有看到 NextCommand 在您的代码中实例化的位置。问题可能存在(禁用它的东西)。
  • 也就是说,我们需要看看NextCommand是什么
  • 您的示例项目不再可用

标签: c# wpf mvvm-light relaycommand


【解决方案1】:

两个字:垃圾收集器

在您的示例项目中——您应该发布相关内容以使您的问题经得起未来考验——您在窗口上设置DataContext,如下所示:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var logic  = new LogicObject();
        DataContext = logic.Collection;
    }
}

因为没有其他东西保留对此处创建的LogicObject 的引用,所以下次有机会时会收集它。

该命令停止运行,因为在LogicObject 中,您将ItemCollectionNextCommand 设置为使用即将收集的LogicObject 的私有成员:

public class LogicObject
{
    public LogicObject()
    {
        Collection = new ItemCollection();
        Collection.NextCommand = new RelayCommand(AddItem, CanAddItem);
        AddItem();
    }

    private bool CanAddItem()
    {
        // snip...
    }

    private void AddItem()
    {
        // snip...
    }
}

收集LogicObject 后,该命令将无法再工作,因为它不再引用有效方法(AddItemCanAddItem)。这就是为什么 RelayCommand 对方法的两个弱引用上的 isAlive 字段都是错误的。

您可以通过坚持使用LogicObject 或将AddItemCanAddItem 方法移到集合中来解决此问题。


为了得到这个问题的 GIF 精神,这里有一个显示按钮在 Gen 0 集合发生后立即停止工作。

【讨论】:

  • 我现在看到了。一直都知道 RelayCommand 使用 Wea​​kActions 和 WeakReferences,但仍然设法错过了我的 LogicObject 没有在其他任何地方引用的部分。感谢你的回答! (顺便说一句,很棒的 gif)
  • 从 MVVMLight 5.4.0 开始,您可以使用 keepTargetAlive 构造函数参数来防止闭包被垃圾回收:mvvmlight.net/doc/weakaction.cshtml
【解决方案2】:

为什么不直接使用 ICollectionView 中的方法?你有:

  • 将当前移动到
  • MoveCurrentToFirst
  • MoveCurrentToLast
  • MoveCurrentToNext
  • MoveCurrentToPrevious
  • 和其他好东西

类似的东西

 private ICollectionView MyView {get;set;}


 this.MyView = CollectionViewSource.GetDefaultView(this._items);


 if (!this.MyView.IsCurrentBeforeFirst)
 {
     this.MyView.MoveCurrentToPrevious();
 }

【讨论】:

  • 你好,盲人。我并不是真的在寻找收集操作。我只是碰巧命名了示例类 ItemCollection 和 Item。代码的关键部分是 NextCommand 属性,可由调用者配置。
猜你喜欢
  • 2010-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多