When View (UserControl) cannot be access from Presenter and burried inside inside a shared DLL, you may use Shell Window
to walk up/down tree. But some docking situation requires using DockLayoutManager to track down.
var shellWindow = _mySvc.GetApplicationShell() as XpfRibbonShellView;
if (shellWindow == null) return;
shellWindow.Dispatcher.Invoke(new Action(() =>
{
try
{
// when TheView is docked
var wrkSpace = VisualTreeHelpers.FindChild<ContentControl>(shellWindow, "wrkSpace");
var gContent = VisualTreeHelpers.FindChild<GroupPaneContentPresenter>(wrkSpace, "PART_Content");
var lpItemsCtl = VisualTreeHelpers.FindChild<LayoutItemsControl>(gContent);
foreach (var i in lpItemsCtl.Items)
{
// TheView docked top layer
var lp = i as LayoutPanel;
if (lp != null && lp.Content is TheView)
lp.ShowCaption = true;
// TheView Tabbed inside another docked
var lg = i as LayoutGroup;
if (lg == null) continue;
foreach (var i2 in lg.Items)
{
var tg = i2 as TabbedGroup;
if (tg != null)
{
var layoutItems = tg.GetItems();
foreach (var lp2 in layoutItems.Cast<LayoutPanel>().Where(lp2 => lp2.Content is TheView))
{
lp2.ShowCaption = true;
}
}
// TheView could end up here if close and then added back whiel in Tab mode
var lp3 = i2 as LayoutPanel;
if (lp3 != null && lp3.Content is TheView)
lp3.ShowCaption = true;
}
}
// When TheView is floating
foreach (var lp in shellWindow.DockLayoutManager.FloatGroups.SelectMany(fg => fg.Items.OfType<LayoutPanel>().Where(lp => lp.Content is TheView)))
{
lp.ShowCaption = true;
}
// All auto hide layout panel need to be handled here , not just TheView.
foreach (var lp in shellWindow.DockLayoutManager.AutoHideGroups.SelectMany(ahGroup => ahGroup.Items).OfType<LayoutPanel>())
{
lp.ShowCaption = true;
}
}
catch (Exception ex)
{
_log.Error(ex);
}
}));
Blog Archive
Tuesday, September 23, 2014
Using DevExpress Layout Manager access a View from Shell
Sunday, September 21, 2014
Low Latency Programing
Looks like their thinking are influenced by Peter Lowery' s Talk on Friday and possibly by
Martin Fowler and Martin Thompson's writing about Low Latency.
I think there are two things highly relevant to Insight-Desktop (Carol, Hai, Daniel, Alec also in Peter's talk so please comment)
(1) Journaling, aka EventSourcing
The idea is to log every input event and replay them to help debug PROD issue in DEV. Obviously, we need a low latency logger
(2) Profile Market watch.
I think Market Data come in here. We should profile for GC pause, Lock contentioin, Caching.
This help us to understand MVVM + Presenter pattern better in term of low latency,
Here are key points from their talk/writing
Setup correct performance test --- Theory are most likely wrong.
GC-Free ---The biggest Performance cost is GC Pause
Lock-Free ---- Lock cause Context switching, clear cache line
Cache Friendly --- L3 Cache is shared memory cross cores.
EventSourcing --- Replay input event to debug PROD in DEV, instead of analysing Log files
Actionable Items:
(1) Performance Benchmark Test App:
A WPF Unit testing simulator can be build for Logging, Journaling, Rx vs. .Net event, Market data <100 micro-second.
(2) Logging Improvement:
a separate email thread already starting writing a logging using RingBuffer.
Shared Memory (L3 cache), Cache Friendly Collectioin
Thread Affinity and Isolation
Queue (LinkedList, Array) Ring Buffer, In Memory
Concurrency
Single Threaded, Fx 4.5 Async-Await
Journaler, Sequential Disk
Array is Cache Friendly.
64-bit Cache key, Concurrent Map/Segments, 1000 Segments. Producer never block to wait consumer
Loop unrolling,Lock-coarsing, Inlining
Queue has fundamental Issues, Ring Buffer is better but on Dsktop cannot have 10M
Network: 10mcs local hop, 10GigE, FPGA market Data
http://mechanical-sympathy.blogspot.hk/
http://martinfowler.com/articles/lmax.html - even martin fowler has done a review of it
http://lmax-exchange.github.io/disruptor/ - all the source code is on github
http://www.infoq.com/presentations/LMAX - presentation on the architecture
Tuesday, September 16, 2014
How to visualize UI hanging using Concurrency Visualizer in VS 2013
Sunday, September 14, 2014
Classical Asyn Pattern and "AsyncRollingFileAppender" using BlockingCollection in Log4Net
Action a = ()=>{ do some work};
a.BeginInvoke(CB, a);
void CB(IAsyncResult ar)
{
Action a = ar.AsyncState as Action;
a.EndInvoke(ar);
}
(1) It seems UI Async cannot be implemented in Fx 4.0.
We have to wait for Fx 4.5 async-await to have non-blocking UI
(2) AsyncRollingFile is "async-like", slightly block UI. In my test it
blocking UI for 9 seconds, then writing file take 40 seconds to complete.
It is definetly faster than classic Log4net RollingFile which block UI by the entire 40 secs.
(3) Log4Net achieved Async by using Task offloading logging from a
queue-like buffer.I also tried TaskCompletionSource and it has similar "short-blocking" async behavior.
(4) All these async-alike can lose 20 seconds of data during delayed write to files since app can crash.
That is when we really need to log why the app crashed.
(5) Fx 4.0 already has a solution to deal with Buffer overflow in Log4NetAsync --- instead of throw away
logging, we can block logging. So we slow down but do no lose data.
Specifically, I think we can implement IProducerConsumer using RingBuffer (so 2x faster writing files)
and feed it to BlockingCollection with Capacity 1000.
I tried BlockingCollection, capacity 10 or 1000, default ConcurrentQueue, end up Blocking UI for 20 secs and
70 sec write to files. so much slower.
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < Int32.MaxValue / 1000; i++)
// your Log.Info
sw.Stop();
MessageBox.Show(sw.ElapsedMilliseconds.ToString());
namespace Log4Net.Async
{
public class AsyncRollingFileAppender : RollingFileAppender
{
BlockingCollection<LoggingEvent> pendingAppends = new BlockingCollection<LoggingEvent>(10);
Task t ;
public override void ActivateOptions()
{
base.ActivateOptions();
t = new Task(AppendLoggingEvents,TaskCreationOptions.PreferFairness);
t.Start();
}
protected override void Append(LoggingEvent[] loggingEvents)
{
Array.ForEach(loggingEvents, Append);
}
protected override void Append(LoggingEvent loggingEvent)
{
Task.Factory.StartNew(() =>
{
if (FilterEvent(loggingEvent))
{
pendingAppends.Add(loggingEvent);
}
});
}
private void AppendLoggingEvents()
{
LoggingEvent loggingEventToAppend;
while (true)
{
while (!pendingAppends.TryTake(out loggingEventToAppend))
{
}
if (loggingEventToAppend == null)
{
continue;
}
try
{
base.Append(loggingEventToAppend);
}
catch
{
}
}
while (pendingAppends.TryTake(out loggingEventToAppend))
{
try
{
base.Append(loggingEventToAppend);
}
catch
{
}
}
}
}
}
Monday, September 1, 2014
MEF Injects UserControls, Property and Method as Action, Func
(1) [ImportMany] handles 0 matching [Export] without blow up
(2) container.GetExportedValueOrDefault trigger IoC DI for Extensions Class
(3) IPartImportsSatisfiedNotification delay construction of property after Ctor.
(4) Obs showed that realtime changes are injected as well.
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
AggregateCatalog aCat = new AggregateCatalog(
new AssemblyCatalog(Assembly.GetExecutingAssembly()),
new DirectoryCatalog(@".\Execution")
);
var container = new CompositionContainer(aCat);
Window w = container.GetExportedValueOrDefault();
w.Show();
}
}
[Export(typeof(Window))]
public partial class MainWindow : Window, IPartImportsSatisfiedNotification
{
[ImportMany("ListUC",typeof(FrameworkElement))]
IEnumerable controls { get; set; }
[ImportMany("WinStyle", typeof(WindowStyle))]
WindowStyle[] WinStyles { get; set; }
[ImportMany("SetWinStyle", typeof(Action))]
Action[] WinStyleActions { get; set; }
public void OnImportsSatisfied()
{
List l = new List(controls);
list.ItemsSource = l; // Xaml code inject a list of UC Controls
if (WinStyles.Length > 0)
WindowStyle = WinStyles[0];
if(WinStyleActions.Length>0)
WinStyleActions[0](this);
}
}
public class MyExtensions
{
[Export("WinStyle", typeof(WindowStyle))]
public WindowStyle WindS
{
get { return WindowStyle.None; }
}
[Export("SetWinStyle")]
public void SetWinStyle(Window w)
{
MessageBox.Show(this.ToString());
Observable.Interval(TimeSpan.FromSeconds(3)).SubscribeOn(SynchronizationContext.Current).Subscribe((s) =>
{
w.Dispatcher.Invoke(new Action(() =>
{
w.WindowStyle = w.WindowStyle == WindowStyle.ThreeDBorderWindow ? WindowStyle.None : WindowStyle.ThreeDBorderWindow;
}));
});
}
}
[Export("ListUC",typeof(FrameworkElement))]
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
}
Subscribe to:
Comments (Atom)

