Created
June 26, 2013 14:11
-
-
Save bradphelan/5867674 to your computer and use it in GitHub Desktop.
ReactiveUI Region control and attached behaviours
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Data; | |
using System.Windows.Documents; | |
using System.Windows.Input; | |
using System.Windows.Markup; | |
using System.Windows.Media; | |
using System.Windows.Media.Imaging; | |
using System.Windows.Navigation; | |
using System.Windows.Shapes; | |
using System.Reactive.Linq; | |
using System.Reactive; | |
using System.Reactive.Disposables; | |
namespace Weingartner.Controls | |
{ | |
/// <summary> | |
/// Attached property inteded to make the target ItemsControl a region | |
/// where controls can be remotely injected. For example a | |
/// region "Master" is defined by an ItemsControl or subclass with an attached | |
/// property | |
/// | |
/// <ItemsControl Region.Region="Master" .... /> | |
/// | |
/// and a control | |
/// | |
/// <wgc:RegionContentControl Region="Master">.... | |
/// | |
/// can provide content for this control from any other view. The content | |
/// is injected on load of the client and removed on unload of the client. | |
/// </summary> | |
public static class Region | |
{ | |
public static readonly DependencyProperty | |
RegionProperty = | |
DependencyProperty.RegisterAttached | |
("Region" | |
, typeof(string) | |
, typeof(Region) | |
, new UIPropertyMetadata | |
("" | |
, RegionUpdated)); | |
public static void SetRegion | |
( ItemsControl dp | |
, string region | |
) | |
{ | |
dp.SetValue(RegionProperty, region); | |
} | |
public static string GetRegion | |
( ItemsControl dp | |
) | |
{ | |
return (string)dp.GetValue(RegionProperty); | |
} | |
public static IDisposable GetRegionSubscription(DependencyObject obj) | |
{ | |
return (IDisposable)obj.GetValue(RegionSubscriptionProperty); | |
} | |
public static void SetRegionSubscription(DependencyObject obj, IDisposable value) | |
{ | |
obj.SetValue(RegionSubscriptionProperty, value); | |
} | |
// Using a DependencyProperty as the backing store for RegionSubscription. This enables animation, styling, binding, etc... | |
public static readonly DependencyProperty RegionSubscriptionProperty = | |
DependencyProperty.RegisterAttached("RegionSubscription", typeof(IDisposable), typeof(Region), new PropertyMetadata(Disposable.Empty)); | |
private static void RegionUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
var itemsControl = d as ItemsControl; | |
if (d == null) | |
{ | |
throw new Exception(d.GetType() + " is not an ItemsControl"); | |
} | |
GetRegionSubscription(itemsControl).Dispose(); | |
var s = ReactiveUI | |
.MessageBus.Current | |
.Listen<RegionMessage>() | |
.Subscribe(message => HandleRegionMessage(itemsControl, message)); | |
SetRegionSubscription(itemsControl, s); | |
} | |
private static void HandleRegionMessage(ItemsControl control, RegionMessage obj) | |
{ | |
if (obj.Region!=GetRegion(control)) | |
{ | |
return; | |
} | |
if (obj.Action==RegionMessage.RegionAction.Add) | |
{ | |
foreach (var item in obj.Controls) | |
{ | |
control.Items.Add(item); | |
} | |
} | |
else | |
{ | |
foreach (var item in obj.Controls) | |
{ | |
control.Items.Remove(item); | |
} | |
} | |
} | |
} | |
public class RegionMessage { | |
public enum RegionAction { | |
Add, | |
Remove, | |
} | |
public string Region { get; set; } | |
public List<object> Controls { get; set; } | |
public RegionAction Action { get; set; } | |
} | |
public class RegionContentControl : ItemsControl | |
{ | |
static RegionContentControl() | |
{ | |
DefaultStyleKeyProperty.OverrideMetadata | |
(typeof(RegionContentControl) | |
, new FrameworkPropertyMetadata(typeof(RegionContentControl))); | |
} | |
public string Region | |
{ | |
get { return (string)GetValue(RegionProperty); } | |
set { SetValue(RegionProperty, value); } | |
} | |
public static readonly DependencyProperty RegionProperty = | |
DependencyProperty.Register | |
("Region" | |
, typeof(string) | |
, typeof(RegionContentControl) | |
, new PropertyMetadata("")); | |
public RegionContentControl() | |
{ | |
this.LoadedObserver().Subscribe(Loaded); | |
this.UnloadedObserver().Subscribe(Unloaded); | |
} | |
private void Unloaded(System.Reactive.EventPattern<RoutedEventArgs> obj) | |
{ | |
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage() | |
{ Action = RegionMessage.RegionAction.Remove | |
, Controls = _HiddenChildren | |
, Region = Region | |
}); | |
} | |
List<object> _HiddenChildren; | |
private void Loaded(System.Reactive.EventPattern<RoutedEventArgs> obj) | |
{ | |
if (_HiddenChildren==null) | |
{ | |
_HiddenChildren = new List<object>(); | |
foreach (var item in Items) | |
{ | |
_HiddenChildren.Add(item); | |
} | |
Items.Clear(); | |
} | |
ReactiveUI.MessageBus.Current.SendMessage(new RegionMessage() | |
{ Action = RegionMessage.RegionAction.Add | |
, Controls = _HiddenChildren | |
, Region = Region | |
}); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment