Я делаю редактор конфигурации для другого приложения и использую отражение для извлечения редактируемых полей из класса конфигурации. Следующий класс является базовым классом для моих различных DataTypeViewModels и показывает, как я получаю и устанавливаю соответствующие свойства.
public abstract class DataTypeViewModel<T> : ViewModelBase
{
Func<T> getFunction;
Action<T> setAction;
public const string ValuePropertyName = "Value";
public string Label { get; set; }
public T Value
{
get
{
return getFunction.Invoke();
}
set
{
if (getFunction.Invoke().Equals(value))
{
return;
}
setAction.Invoke(value);
// Update bindings, no broadcast
RaisePropertyChanged(ValuePropertyName);
}
}
/// <summary>
/// Initializes a new instance of the StringViewModel class.
/// </summary>
public DataTypeViewModel(string sectionName, string label)
{
if (IsInDesignMode)
{
// Code runs in Blend --> create design time data.
}
else
{
Label = label;
getFunction = new Func<T>(() =>
{
return (T)Settings.Instance.GetType().GetProperty(sectionName).PropertyType.
GetProperty(label).GetValue(Settings.Instance.GetType().GetProperty(sectionName).GetValue(Settings.Instance, null), null);
});
setAction = new Action<T>(value =>
{
Settings.Instance.GetType().GetProperty(sectionName).PropertyType.GetProperty(label).
SetValue(Settings.Instance.GetType().GetProperty(sectionName).GetValue(Settings.Instance, null), value, null);
});
}
}
}
Эта часть работает так, как я хочу, следующая часть представляет собой образец DataTypeViewModel в списке строк.
public class StringListViewModel : DataTypeViewModel<ICollection<string>>
{
/// <summary>
/// The <see cref="RemoveItemCommand" /> property's name.
/// </summary>
public const string RemoveItemCommandPropertyName = "RemoveItemCommand";
private RelayCommand<string> _removeItemCommand = null;
public ObservableCollection<string> ObservableValue { get; set; }
/// <summary>
/// Gets the RemoveItemCommand property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public RelayCommand<string> RemoveItemCommand
{
get
{
return _removeItemCommand;
}
set
{
if (_removeItemCommand == value)
{
return;
}
var oldValue = _removeItemCommand;
_removeItemCommand = value;
// Update bindings, no broadcast
RaisePropertyChanged(RemoveItemCommandPropertyName);
}
}
/// <summary>
/// The <see cref="AddItemCommand" /> property's name.
/// </summary>
public const string AddItemCommandPropertyName = "AddItemCommand";
private RelayCommand<string> _addItemCommand = null;
/// <summary>
/// Gets the AddItemCommand property.
/// TODO Update documentation:
/// Changes to that property's value raise the PropertyChanged event.
/// This property's value is broadcasted by the Messenger's default instance when it changes.
/// </summary>
public RelayCommand<string> AddItemCommand
{
get
{
return _addItemCommand;
}
set
{
if (_addItemCommand == value)
{
return;
}
var oldValue = _addItemCommand;
_addItemCommand = value;
// Update bindings, no broadcast
RaisePropertyChanged(AddItemCommandPropertyName);
}
}
/// <summary>
/// Initializes a new instance of the StringListViewModel class.
/// </summary>
public StringListViewModel(string sectionName, string label) : base(sectionName, label)
{
ObservableValue = new ObservableCollection<string>(Value);
AddItemCommand = new RelayCommand<string>(param =>
{
if (param != string.Empty)
{
Value.Add(param);
ObservableValue.Add(param);
}
});
RemoveItemCommand = new RelayCommand<string>(param =>
{
if (param != null)
{
Value.Remove(param);
ObservableValue.Remove(param);
}
});
}
}
Как вы можете видеть в конструкторе, у меня в настоящее время есть «Значение», отраженное в новую коллекцию ObservableCollection под названием «ObservableValue», которая затем связывается с ListView в XAML. Это хорошо работает, но клонирование списка кажется таким хакерским способом сделать это. Несмотря на привязку к значению, я попытался добавить:
RaisePropertyChanged("Value");
для AddItemCommand и RemoveItemCommand, но это не работает, ListView не будет обновляться. Как правильно это сделать?