Непоследовательное поведение: MVVM RelayCommandWPF с закрытием, захватывающим локальную переменную - PullRequest
0 голосов
/ 07 декабря 2018

Я пытаюсь понять какое-то странное поведение, которое я наблюдаю с помощью MVVM RelayCommand, действие которого является замыканием, захватывающим локальную переменную.

Пример минимального жизнеспособного кода:

using GalaSoft.MvvmLight.CommandWpf;

namespace WpfApplication3
{
    public partial class MainWindow
    {
        public RelayCommand DoIt { get; }

        int i = 0;

        public MainWindow()
        {
            DoIt = new RelayCommand( () =>
            {
                System.Console.WriteLine( "doing it!" );
                button.Content = (++i).ToString();
            } );

            InitializeComponent();
        }
    }
}

XAML:

<Window x:Class="WpfApplication3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        SizeToContent="WidthAndHeight">
    <Button x:Name="button" Content="Hit me" Command="{Binding DoIt, RelativeSource={RelativeSource AncestorType=Window}}"/>
</Window>

Когда вы нажимаете кнопку «Ударь меня», метка меняется на число, которое увеличивается с каждым последующим нажатием.

Поскольку i используется только RelayCommand action, я хочу переместить объявление в constructur как локальную переменную.Но когда я это делаю, я получаю очень странное поведение: команда либо вообще не запускается, либо запускается один раз, а затем останавливается.

Интересно, что если я откажусь от RelayCommand и подключу замыкание ксобытие кнопки Click, оно работает независимо от того, где я определяю i.Так что, должно быть, что-то в том, как RelayCommand обрабатывает замыкание.

Есть предположения?

1 Ответ

0 голосов
/ 11 июля 2019

Проблема заключается в том, что закрытие, передаваемое команде, в конечном итоге собирается мусором.Закажите этот ответ о переполнении стека и MVVMLight документацию .

Действие команды и функция включения, которые вы передаете RelayCommand, хранятся со слабыми ссылками, поэтому, если что-то кроме RelayCommand не удержит их, они в какой-то момент будут собираться мусором.Решение состоит в том, чтобы использовать параметр конструктора keepTargetAlive, если ваши действие или функция включения являются замыканиями.

...