#c# #xml #wpf #validation #data-binding
#c# #xml #wpf #проверка #привязка данных
Вопрос:
У меня есть приложение wpf с конфигурационным файлом xml.
Я создал класс ViewModel, который привязан к MainWindow.xaml, и я создаю несколько валидаторов, используя IDataErrorInfo и класс ValidationRule.
Чего я хочу, так это того, что если пользователь изменяет значение, и это значение проходит проверку, класс config становится сериализованным в xml.
Для сохранения у меня есть расширение класса:
public static class ConfiguracionExtension
{
public static void Save(this Configuration configXML)
{
string ConfigPath = AppDomain.CurrentDomain.BaseDirectory "config.xml";
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream writer = new FileStream(ConfigPath, FileMode.Create);
ns.Add("", "");
serializer.Serialize(writer, configXML, ns);
writer.Close();
}
}
Класс конфигурации выглядит следующим образом:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
OnPropertyChanged("minute");
}
}
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
return (Configuration)_s.Deserialize(new XmlTextReader(ConfigPath));
}
catch (Exception ex)
{
Auxiliar.writeError(ex.ToString());
return new Configuration();
}
}
else
return new Configuration();
}
public Configuracion()
{
minutes = 60;
}
#region IDataErrorInfo Members
public string Error
{
get { return String.Empty; }
}
public string this[string columnName]
{
get
{
String errorMessage = String.Empty;
switch (columnName)
{
case "minute":
if (minute < 1)
{
errorMessage = "minutes can't be less than 1";
}
break;
}
return errorMessage;
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
и правило проверки выглядит следующим образом:
public class MinutesValidation : ValidationRule
{
private int _min;
public int Minimum
{
get { return _min; }
set { _min = value; }
}
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
int minute;
Boolean noIllegalChars;
noIllegalChars = int.TryParse(value.ToString(), out minute);
if (value.ToString().Length < 1)
{
return new ValidationResult(false, "Value can't be empty");
}
else if (noIllegalChars == false)
{
return new ValidationResult(false, "Ilegal Character");
}
else
{
return new ValidationResult(true, null);
}
}
}
Комментарии:
1. неясно, в чем проблема. Почему вы не можете просто вызвать Save в установщике измененного свойства?
2. Я получаю систему. Windows. Разметка. Исключение XamlParseException, я думаю, я могу вызвать сериализацию для набора, потому что набор вызывается при десериализации. Кроме того, set вызывается каждый раз, когда свойство получает данные, но проверка вызывается только тогда, когда пользователь вводит данные.
3. Если вам нужно определить, изменено ли свойство пользователем или программно, у вас, вероятно, должно быть два свойства. Одно из них является основным свойством, а другое предназначено только для привязки с проверкой, а второе обертывает первое.
4. Итак, нет способа вызвать функцию сохранения, когда ValidationResult имеет значение true?
Ответ №1:
Хорошо, я решил, но если у кого-нибудь найдется вариант получше, я буду очень благодарен.
Что я сделал, так это то, что в конфигурационный файл я добавил загруженное логическое значение, которое начинается с false , и я добавил условие к функции сохранения, чтобы она работала только тогда, когда загруженное значение равно true.
Теперь класс конфигурации выглядит следующим образом:
[Serializable, XmlRoot("configuration")]
public class Configuration : IDataErrorInfo, INotifyPropertyChanged
{
private int _minute;
[XmlElement]
public int minute
{
get
{
return _minute;
}
set
{
_minute = value;
this.Save();
OnPropertyChanged("minute");
}
}
[XmlIgnore]
public bool loaded;
public static Configuration Load()
{
string ConfigPath= AppDomain.CurrentDomain.BaseDirectory "config.xml";
if (File.Exists(ConfigPath))
{
try
{
XmlSerializer _s = new XmlSerializer(typeof(Configuration));
var tempConf = (Configuracion)_s.Deserialize(new XmlTextReader(ConfigPath));
tempConf.loaded = false;
return tempConf;
}
[...]
}
public Configuracion()
{
loaded = false;
minutes = 60;
}
[...]
}
Я добавил событие loaded в главное окно, и когда оно запускается, оно присваивает свойству loaded значение true.