Skip to content

Instantly share code, notes, and snippets.

@bradphelan
Created June 26, 2013 14:11
Show Gist options
  • Save bradphelan/5867674 to your computer and use it in GitHub Desktop.
Save bradphelan/5867674 to your computer and use it in GitHub Desktop.
ReactiveUI Region control and attached behaviours
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