Обработчик события не запускает измененное свойство - PullRequest
0 голосов
/ 22 октября 2018

У меня есть приложение WPF, и я хочу, чтобы элемент управления «Пуск» был включен только в том случае, если в текстовом поле «Путь к загрузке» было указано значение.

Моя ViewModel содержит свойство для моей модели »ConfigurationSettings "и реализация ICommand (CommandImp) для кнопки:

public class MainWindowViewModel : BaseNotifyPropertyChanged
{        
    private ConfigurationSettings _configurationSettings { get; set; }
    public ConfigurationSettings ConfigurationSettings 
    {
        get
        {
            return _configurationSettings;
        }
        set
        {
            if (_configurationSettings != value)
            {
                _configurationSettings = value;
                RaisePropertyChanged("ConfigurationSettings");
            }
        }
    }

    public CommandImp StartCommand { get; set; } // this is an implementation of ICommand

    public MainWindowViewModel()
    {
        StartCommand = new CommandImp(OnStart, CanStart);

        _configurationSettings = new ConfigurationSettings();
        _configurationSettings.PropertyChanged += delegate (object o, 
                PropertyChangedEventArgs args)
        {                
            StartCommand.RaiseCanExecuteChanged(); // break point here is never reached            
        };            
    }

    private bool CanStart()
    {
        if (!String.IsNullOrEmpty(ConfigurationSettings.DownloadPath))
        {
            return true;
        }
        return false;
    }
}

В моем XAML есть кнопка« Пуск »и команда with Command =« {Binding StartCommand} ».

Мои параметры конфигурацииУ класса просто есть строка для DownloadPath, которая связана с текстовым полем в XAML:

public class ConfigurationSettings : BaseNotifyPropertyChanged
{
    private string _downloadPath { get; set; }
    public string DownloadPath
    {
        get { return _downloadPath; }
        set
        {
            if (_downloadPath != value)
            {
                _downloadPath = value;
                RaisePropertyChanged("DownloadPath"); // break point here IS reached
            }
        }
    }
} 

Когда пользователь вводит DownloadPath, я ожидаю, что он вызовет событие PropertyChanged и запустит мой метод делегата, определенныйв конструкторе ViewModel.

Если переместить командную кнопку внутри класса ConfigurationSettings, я могу покончить с подпиской на событие и просто использовать StartCommand.RaiseCanExecuteChanged () прямо под RaisePropertyChanged ("DownloadPath") ;.Но я не хочу, чтобы ICommand был частью моей модели.

Как я могу вызвать CanStart () при изменении одного из свойств ConfigurationSettings?

ОБНОВЛЕНИЕ: Вот XAML дляпривязка текстового поля:

<TextBlock Text="{Binding ConfigurationSettings.DownloadPath, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" TextWrapping="WrapWithOverflow" />

и кнопка:

<Button Content="Start" Command="{Binding StartCommand}"></Button>

Следует отметить, что привязки работают правильно.Когда я обновляю текстовый блок, я вижу в ViewModel, что ConfigurationSettings.DownloadPath корректно обновляется.

BaseNotifyPropertyChanged является реализацией INotifyPropertyChanged следующим образом:

public class BaseNotifyPropertyChanged : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string property)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
}

мне не кажетсяиметь какие-либо проблемы с измененным свойством события.Я могу поставить точку останова здесь, и она будет достигнута, когда я обновлю текстовое поле DownloadPath.Когда я подписываюсь на это событие PropertyChanged в конструкторе ViewModel, мой метод делегата не запускается.

1 Ответ

0 голосов
/ 24 октября 2018

Ненавижу отвечать на мой собственный вопрос, но комментирующие люди заставили меня задуматься о реструктуризации моего вопроса - что привело меня к ответу, прежде чем мне нужно было сделать еще одно обновление.

Решением было перенести мою подписку на события внутриФункция 'set' для ConfigurationSettings:

private ConfigurationSettings _configurationSettings { get; set; }
public ConfigurationSettings ConfigurationSettings
{
    get
    {
        return _configurationSettings;
    }
    set
    {
        if (_configurationSettings != value)
        {
            _configurationSettings = value;

            _configurationSettings = new Model.ConfigurationSettings();
            _configurationSettings.PropertyChanged += (o, args) =>
            {
                StartCommand.RaiseCanExecuteChanged();
            };

            RaisePropertyChanged("ConfigurationSettings");                   
        }
    }
}

Проблема заключалась в том, что я устанавливал свой контекст данных, который я изначально не подозревал, был проблемой вообще.Я загружаю модель представления из файла XML на диск.И когда приложение закрыто, я перезаписываю этот файл последней версией ViewModel.

В конструкторе, который я читал и устанавливал DataContext:

public MainWindowView()
{
    InitializeComponent();

    string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
    DataSourcePath = new Uri(System.IO.Path.Combine(appPath, DataFileName));

    if (File.Exists(DataSourcePath.LocalPath))
    {
        XmlReader reader = XmlReader.Create(DataSourcePath.LocalPath);
        DataContext = (MainWindowViewModel)serialize.Deserialize(reader);
        reader.Close();
    }
    else
    {
        WriteDataViewModelToDisk(); // new empty view model written to disk
    }
}

Если это был первый раз, когда я запускал код без ранее существующего файла, мой обработчик события делегата фактически работал,Проблема заключалась в том, что когда этот код загружал ранее существующий XML-файл, он перезаписывал свойство ConfigurationSettings в моей модели представления, тем самым уничтожая подписку на событие.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...