Я бы включил это в функции:
awk '
function next_month(year, month) {
month++;
if (month == 13) {
year++;
month = 1;
}
return sprintf "%d-%02d", year, month;
}
function previous_month(year, month) {
month--;
if (month == 0) {
year--;
month = 12;
}
return sprintf "%d-%02d", year, month;
}
BEGIN {
year = 2019; month = 1;
printf "%d-%d\t%s\t%s\n",
year, month,
next_month(year, month),
previous_month(year, month);
year = 2018; month = 12;
printf "%d-%d\t%s\t%s\n",
year, month,
next_month(year, month),
previous_month(year, month);
}
'
2019-1 2019-02 2018-12
2018-12 2019-01 2018-11
Я предполагаю, что вы предоставляете действительный ввод для функций. Валидация оставлена в качестве упражнения.
Удалите параметры функции, чтобы изменить переменные в глобальной области видимости.
Вот класс, который будет обернуть INOTIFYPROPERTYCHANDED, пересылайте мероприятие по недействию через SynchronizationContext.Courent и пересылать свойство.
Это решение должно работать, но в некотором времени можно улучшить, чтобы использовать лямбда экспрессию вместо имени свойства. Это позволило бы избавиться от отражения, предоставить напечатанный доступ к собственности. Усложнение с этим вам нужно также получить дерево выражения из лямбда, чтобы вытащить имя свойства, чтобы вы могли использовать его в методе OnsourcePropertyChanged. Я видел сообщение о том, чтобы потянуть имя недвижимости из дерева выражения лямбда, но я не мог найти это только сейчас.
Чтобы использовать этот класс, вы хотели бы изменить свое привязку:
Bindings.Add("TargetProperty", new SyncBindingWrapper<PropertyType>(source, "SourceProperty"), "Value");
и вот синхронизация:
using System.ComponentModel;
using System.Reflection;
using System.Threading;
public class SyncBindingWrapper<T> : INotifyPropertyChanged
{
private readonly INotifyPropertyChanged _source;
private readonly PropertyInfo _property;
public event PropertyChangedEventHandler PropertyChanged;
public T Value
{
get
{
return (T)_property.GetValue(_source, null);
}
}
public SyncBindingWrapper(INotifyPropertyChanged source, string propertyName)
{
_source = source;
_property = source.GetType().GetProperty(propertyName);
source.PropertyChanged += OnSourcePropertyChanged;
}
private void OnSourcePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != _property.Name)
{
return;
}
PropertyChangedEventHandler propertyChanged = PropertyChanged;
if (propertyChanged == null)
{
return;
}
SynchronizationContext.Current.Send(state => propertyChanged(this, e), null);
}
}
Не полагаясь на SynchrnoisationConext можно полагаться на ISynchronizeInvoke
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
foreach (EventHandler h in handler.GetInvocationList())
{
var synch = h.Target as ISynchronizeInvoke;
if (synch != null && synch.InvokeRequired)
synch.Invoke(h, new object[] { this, e });
else
h(this, e);
}
}
}