Conditions and facts

time to read 2 min | 373 words

When working with UI, quite often some part of the UI is dependant on some condition. The problem is that this condition is often subject to change, and we need some way of dealing with those changes. That is why I created the following class:

public class Fact : INotifyPropertyChanged
{
	private readonly Func<bool> predicate;

	public Fact(INotifyPropertyChanged observable, Func<bool> predicate)
	{
		this.predicate = predicate;
		observable.PropertyChanged += (sender, args) =>
		                              PropertyChanged(this, new PropertyChangedEventArgs("Value"));
	}

	public bool Value
	{
		get
		{
			return predicate();
		}
	}

	public event PropertyChangedEventHandler PropertyChanged = delegate { };
}

While it doesn’t looks like much, it does offer me a lot of value in terms of simplifying conditional logic. For example:

public Fact CanMovePrev
{
	get { return new Fact(CurrentPage, () => CurrentPage > 0); }
}

public void OnMovePrev()
{
	LoadPage(CurrentPage - 1);
}

Where CurrentPage is an Observable<T>, which I discussed previously.

My infrastructure knows about the naming convention and will automatically generate a Command and bind it to the MovePrev action, including both the action to execute upon commit and whatever or not we can execute this. For that matter, it will also gracefully handle can execute changes very easily. Here is the code to actually do that (I’ll spare you the convention based wiring code):

public class DelegatingCommand : ICommand
{
	private readonly Action action;
	private readonly Fact canExecute;

	public DelegatingCommand(Action action, Fact canExecute)
	{
		this.action = action;
		this.canExecute = canExecute;
		var dispatcher = Dispatcher.CurrentDispatcher;
		if (canExecute != null)
		{
			this.canExecute.PropertyChanged +=
				(sender, args) =>
					dispatcher.Invoke(CanExecuteChanged, this, EventArgs.Empty);
		}
	}

	public void Execute(object parameter)
	{
		action();
	}

	public bool CanExecute(object parameter)
	{
		if (canExecute == null)
			return true;
		return canExecute.Value;
	}

	public event EventHandler CanExecuteChanged = delegate { };
}

Tada! :-)