Обновление привязки данных, но представление не - PullRequest
0 голосов
/ 02 июня 2018

У меня есть свойство ( FileName ), которое прекрасно обновляется, когда я смотрю его в отладчике (при наведении указателя мыши на свойство как в модели представления, так и в XAML), но пользовательский интерфейс будетне отражать значение обновления.У меня установлена ​​точка останова на set { this.MutateVerbose(ref _fileName, value, RaisePropertyChanged()); }, и я могу наблюдать, как она вводится и выдает уведомление об изменении через RaisePropertyChanged().

Я создаю его экземпляр с начальным значением «Не обновлено» с помощью FileName = "Not Updated";, и хотя свойство успешно обновляется до других значений в течение времени выполнения приложения с помощью FileName = SelectRandomString();, пользовательский интерфейс никогда не обновляется.Соответствующий код пользовательского интерфейса:

                            <TextBlock Text="{Binding FileName}" HorizontalAlignment="Center">
                            <TextBlock.DataContext>
                                <ns:ProgressViewModel />
                            </TextBlock.DataContext>
                        </TextBlock>

Модель полного просмотра:

using MaterialDesignThemes.Wpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;

namespace MaterialDesignTest
{
    public class ProgressViewModel : INotifyPropertyChanged
    {

    System.Windows.Forms.Timer progressTimer;

    private double _saveProgressButton;
    public double SaveProgressButton
    {
        get { return _saveProgressButton; }
        set { this.MutateVerbose(ref _saveProgressButton, value, RaisePropertyChanged()); }
    }

    private string _fileName;
    public string FileName
    {
        get { return _fileName; }
        set { this.MutateVerbose(ref _fileName, value, RaisePropertyChanged()); }
    }

    private bool _isSaveComplete;
    public bool IsSaveComplete
    {
        get { return _isSaveComplete; }
        private set { this.MutateVerbose(ref _isSaveComplete, value, RaisePropertyChanged()); }
    }

    private bool _isSaving;
    public bool IsSaving
    {
        get { return _isSaving; }
        private set { this.MutateVerbose(ref _isSaving, value, RaisePropertyChanged()); }
    }

    int progress = 0;
    int cycles = 0;
    public ProgressViewModel()
    {
        FileName = "Not Updated";

    }
    public void KickOffProgressTimer()
    {
        progressTimer = new System.Windows.Forms.Timer();
        progressTimer.Tick += new EventHandler(progressTimerTick);
        progressTimer.Interval = 40;
        progressTimer.Start();
    }

    private async void progressTimerTick(object sender, EventArgs e)
    {
        FileName = SelectRandomString();

        if (progress < 100 && cycles < 2)
        {
            if (progress == 99)
            {
                cycles++;
                progress = 0;
            }

            IsSaveComplete = false;
            IsSaving = true;
            progress++;
            SaveProgressButton = progress;
        }
        else
        {
            IsSaveComplete = true;
            IsSaving = false;
            progressTimer.Enabled = false;
            SaveProgressButton = 0;

            await NonBlockingDelay(1750);

            DialogHost.CloseDialogCommand.Execute(null, null);
        }
    }
    async Task NonBlockingDelay(int value)
    {
        await Task.Delay(value);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private Action<PropertyChangedEventArgs> RaisePropertyChanged()
    {
        return args => PropertyChanged?.Invoke(this, args);
    }

    static string SelectRandomString()
    {
        var random = new Random();
        var questions = new List<string>{
            @"C:\Files\Filename1",
            @"C:\Filename2",
            @"C:\Filename3",
            @"C:\Filename4",
            @"C:\Temp\Files\Filename5",
            @"C:\Filename6",
            @"C:\Demo\LongFolderName\Filename7",
            @"C:\Filename8",
            @"C:\Filename9",
        };
        int index = random.Next(questions.Count);
        return(questions[index]);
    }
}

}

Код для MutateVerbose:

        public static void MutateVerbose<TField>(this INotifyPropertyChanged instance, ref TField field, TField newValue, Action<PropertyChangedEventArgs> raise, [CallerMemberName] string propertyName = null)
        {
        if (EqualityComparer<TField>.Default.Equals(field, newValue)) return;
        field = newValue;
        raise?.Invoke(new PropertyChangedEventArgs(propertyName));
        }

Обновление : если я начнутаймер выполнения как часть загрузки модели представления выглядит так:

        public ProgressViewModel()
        {
        KickOffProgressTimer();
        }

Интерфейс обновляется в соответствии с требованиями.Но я не понимаю этого поведения, и это нежелательно.Я не хочу, чтобы метод KickOffProgressTimer(); выполнялся сразу после запуска приложения, а только при нажатии кнопки из кода главного окна:

        private void CircleButtonClick(object sender, RoutedEventArgs e)
        {
           ProgressViewModel pvm = new ProgressViewModel();
           CircleButton.DataContext = pvm;
           pvm.KickOffProgressTimer();
        }

Ответы [ 2 ]

0 голосов
/ 02 июня 2018

Это может быть способ, которым вы поднимаете событие измененного свойства.Вы пытались использовать новую реализацию PropertyChanged, которая была добавлена ​​для C# 6.0.Я сократил ваш код до следующего, и он отлично работает.

public class ProgressViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _fileName;
    public string FileName
    {
        get { return _fileName; }
        set
        {
            _fileName = value;
            OnPropertyChanged();
        }
    }

    public ProgressViewModel()
    {
        var random = new Random();
        var timer = new Timer
        {
            Interval = 200,
        };

        timer.Elapsed += (s, e) => FileName = random.Next().ToString();
        timer.Start();
    }
}
0 голосов
/ 02 июня 2018

Необходимо указать UpdateSourceTrigger событие, которое будет запускать обновление пользовательского интерфейса:

<TextBlock Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}" ...
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...