public class Setting
{
public string Setting1 {get;set;}
}
public class SettinngViewModel: ViewModelBase
{
public SettingViewModel(Setting settings)
{
_settings = settings;
}
Setting _settings {get; private set;}
public string Setting1
{
get {return setting1;}
set {setting1=value; OnPropertyChanged("Setting1")}
}
}
собственно вопрос в следующем: есть главная форма из которой вызывается данное окно редактирования настроек
public MainViewModel
{
public MainViewModel()
{
SettingsCommand = new RelayCommand(x=>SettingsMethod());
}
var currentSettings = //здесь хранятся текущие настройки
public ICommand SettingsCommand {get; private set;}
private void SettingsMethod()
{
var view = new SettingsView();
view.DataContext = new SettingsViewModel(currentSettings);
view.Show();
}
}
ввиду того что settings это ссылочный тип то при изменении в окне настроек изменения сразу отражаются в главной форме, а я бы хотел что бы это было только после подтверждения(например пользователь нажимает кнопку Применить)
помогите реализовать соответствующую команду
Ответ
Смотрите.
Если вы редактируете настройки, вы редактируете, понятно, копию настроек, а не оригинал. В WinForms это скрывалось за тем фактом, что применение изменений происходило во View, но с WPF/MVVM правильный подход такой.
Рассмотрим случай, когда у вас нет VM-объекта, отвечающего за настройки, который поддерживает свои поля в актуальном состоянии. Тогда вам нужен VM-объект «редактируемые настройки» (SettingsEditorVM), который при старте считывает свои свойства из модельного объекта, но не синхронизирует их с моделью при изменениях. Он также выставляет команду «окончить редактирование», по приходу которой проверяет настройки на правильность, и если они в порядке, записывает результат в модельный объект.
Для случая, когда у вас уже есть VM-объект, отвечающий за настройки (SettingsVM), который поддерживает свои поля в актуальном состоянии, вам нужно всё равно завести ещё один VM-объект «редактируемые настройки» (SettingsEditorVM), который сможет загрузить данные (например, в конструкторе) из SettingsVM, и по команде закончить редактирование.
Этим можно пользоваться так:
public class SettinngEditorVM : ViewModelBase
{
public SettinngEditorVM(SettingVM settingsVM)
{
FinishedEditing = new AwaitableCommand();
CancelledEditing = new AwaitableCommand();
Setting1 = settingsVM.Setting1;
}
string setting1;
public string Setting1
{
get { return setting1; }
set
{
setting1 = value;
OnPropertyChanged("Setting1");
CheckCorrectness();
}
}
void CheckCorrectness()
{
bool ok = Setting1 != null;
FinishedEditing.CanExecuteInternal = ok;
}
public AwaitableCommand FinishEditing { get; private set; }
public AwaitableCommand CancelledEditing { get; private set; }
public async Task
с таким вызовом:
var editorVM = new SettingsEditorVM(editorVM);
var task = editorVM.Edit();
var editorWindow = new EditorWindow() { DataContext = editorVM };
editorWindow.Show();
var succeeded = await task;
if (succeeded)
settingsVM.LoadFrom(editorVM);
Заметьте, что код у SettingsEditorVM и SettingsVM практически одинаков, так что эти два класса стоит объединить в один.
Вот код AwaitableCommand
class AwaitableCommand : ICommand
{
bool canExecute;
// не придумал названия получше
public bool CanExecuteInternal
{
get
{
return canExecute;
}
set
{
if (canExecute == value)
return;
canExecute = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, new EventArgs());
}
}
public bool CanExecute(object parameter)
{
return canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
foreach (var tcs in subscribers)
tcs.TrySetResult(true);
subscribers.Clear();
}
List
public async Task TillActivation(CancellationToken ct)
{
var tcs = new TaskCompletionSource
Комментариев нет:
Отправить комментарий