diff --git a/src/Gemini.Demo/Gemini.Demo.csproj b/src/Gemini.Demo/Gemini.Demo.csproj
index a69fa219..6b2d4890 100644
--- a/src/Gemini.Demo/Gemini.Demo.csproj
+++ b/src/Gemini.Demo/Gemini.Demo.csproj
@@ -44,6 +44,9 @@
true
+
+ ..\packages\C5.2.3.0.1\lib\net40\C5.dll
+
..\packages\Caliburn.Micro.Core.2.0.2\lib\net45\Caliburn.Micro.dll
True
@@ -52,6 +55,15 @@
..\packages\Caliburn.Micro.2.0.2\lib\net45\Caliburn.Micro.Platform.dll
True
+
+ ..\packages\Common.Logging.2.2.0\lib\net40\Common.Logging.dll
+
+
+ ..\packages\Common.Logging.Core.2.2.0\lib\net40\Common.Logging.Core.dll
+
+
+ ..\packages\Gridsum.DataflowEx.1.1.3\lib\net45\Gridsum.DataflowEx.dll
+
..\packages\Gu.Localization.6.1.0.0\lib\net45\Gu.Localization.dll
True
@@ -81,18 +93,46 @@
True
-
- ..\packages\System.Collections.Immutable.1.1.37\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
+
+ ..\packages\System.Collections.Immutable.1.3.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll
True
+
+ ..\packages\System.Interactive.Async.3.1.1\lib\net46\System.Interactive.Async.dll
+
+
+ ..\packages\System.Reactive.Core.3.1.1\lib\net45\System.Reactive.Core.dll
+
+
+ ..\packages\System.Reactive.Interfaces.3.1.1\lib\net45\System.Reactive.Interfaces.dll
+
+
+ ..\packages\System.Reactive.Linq.3.1.1\lib\net45\System.Reactive.Linq.dll
+
+
+ ..\packages\System.Reactive.PlatformServices.3.1.1\lib\net45\System.Reactive.PlatformServices.dll
+
+
+ ..\packages\System.Reactive.Windows.Threading.3.1.1\lib\net45\System.Reactive.Windows.Threading.dll
+
+
+ ..\packages\System.Reflection.4.1.0\lib\net462\System.Reflection.dll
+
..\packages\System.Reflection.Metadata.1.1.0\lib\portable-net45+win8\System.Reflection.Metadata.dll
True
+
+ ..\packages\System.Threading.Tasks.Dataflow.4.7.0\lib\portable-net45+win8+wpa81\System.Threading.Tasks.Dataflow.dll
+
+
+ ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll
+
+
@@ -150,6 +190,8 @@
+
+
@@ -158,22 +200,32 @@
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
GraphView.xaml
+
+ ImagePreview.xaml
+
@@ -286,6 +338,10 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -332,6 +388,7 @@
+
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs b/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs
new file mode 100644
index 00000000..bcdb88c1
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/JoinAnyBlock.cs
@@ -0,0 +1,41 @@
+using Gridsum.DataflowEx;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+
+namespace Gemini.Demo.Modules.FilterDesigner
+{
+ public class JoinAny
+ {
+ public Task Completion => throw new NotImplementedException();
+ public Dataflow Target1;
+ public Dataflow Target2;
+ public Dataflow<(T1, T2), (T1, T2)> source;
+ public bool first;
+ T1 I1;
+ T2 I2;
+ public JoinAny()
+ {
+ Target1 = new BufferBlock(new DataflowBlockOptions()).ToDataflow();
+ Target2 = new BufferBlock(new DataflowBlockOptions()).ToDataflow();
+ Target1.OutputBlock.AsObservable().Subscribe(x => _in1(x));
+ Target2.OutputBlock.AsObservable().Subscribe(x => _in2(x));
+
+ source = new BufferBlock<(T1, T2)>().ToDataflow();
+
+ }
+ private void _in2(T2 x)
+ {
+ I2 = x;
+ if (I1 != null) source.SendAsync((I1, I2));
+ }
+ private void _in1(T1 x)
+ {
+ I1 = x;
+ if (I2 != null) source.SendAsync((I1, I2));
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs b/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs
new file mode 100644
index 00000000..ac8d229e
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/Logger.cs
@@ -0,0 +1,45 @@
+using Common.Logging.Simple;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Common.Logging;
+using Common.Logging.Factory;
+using System.ComponentModel.Composition;
+using Gemini.Modules.ErrorList;
+
+namespace Gemini.Demo.Modules.FilterDesigner
+{
+ public class Logger : AbstractLogger
+ {
+ public override bool IsTraceEnabled => true;
+
+ public override bool IsDebugEnabled => true;
+
+ public override bool IsInfoEnabled => true;
+
+ public override bool IsWarnEnabled => true;
+
+ public override bool IsErrorEnabled => true;
+
+ public override bool IsFatalEnabled => true;
+
+ IErrorList _display;
+
+
+ public Logger(IErrorList display)
+ {
+ _display = display;
+ }
+
+
+ protected override void WriteInternal(LogLevel level, object message, Exception exception)
+ {
+
+ if(message !=null) _display.AddItem(ErrorListItemType.Message, message.ToString());
+ if(exception != null) _display.AddItem(ErrorListItemType.Error, exception.ToString());
+
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs b/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs
new file mode 100644
index 00000000..97e89f69
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/LoggerFacory.cs
@@ -0,0 +1,31 @@
+using Common.Logging.Factory;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.Composition;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Common.Logging;
+using Gemini.Modules.ErrorList;
+
+namespace Gemini.Demo.Modules.FilterDesigner
+{
+ [Export(typeof(LoggerFacory))]
+ public class LoggerFacory : AbstractCachingLoggerFactoryAdapter
+ {
+ Logger l;
+ IErrorList _display;
+
+ [ImportingConstructor]
+ public LoggerFacory(IErrorList display)
+ {
+ _display = display;
+ }
+
+
+ protected override ILog CreateLogger(string name)
+ {
+ return l = l ?? new Logger(_display);
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs
new file mode 100644
index 00000000..a7594402
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/BitmapSourceConnection.cs
@@ -0,0 +1,26 @@
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection
+{
+ class BitmapSourceConnection : GenericConnectionViewModel
+ {
+ public BitmapSourceConnection(GenericOutputConnectorViewModel from, GenericInputConnectorViewModel to) :base(from,to)
+ {
+ }
+
+ public BitmapSourceConnection(GenericOutputConnectorViewModel from) : base(from)
+ {
+ }
+
+ Brush __color = new SolidColorBrush(System.Windows.Media.Color.FromRgb(36, 97, 121));
+ internal override Brush _color { get { return __color; } set { __color = value; } }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs
similarity index 67%
rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs
rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs
index 90b4a8c1..73aea21f 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectionViewModel.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/ConnectionViewModel.cs
@@ -1,17 +1,22 @@
using System;
using System.Windows;
using Caliburn.Micro;
+using System.Windows.Media;
+using System.ComponentModel;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
{
- public class ConnectionViewModel : PropertyChangedBase
+ public abstract class ConnectionViewModel : PropertyChangedBase, IsSelectable
{
- private OutputConnectorViewModel _from;
+ public abstract Type ConnectionType { get; set; }
+
+ internal abstract OutputConnectorViewModel _from { get; set; }
public OutputConnectorViewModel From
{
get { return _from; }
private set
{
+ if (value.Type != ConnectionType) throw new Exception();
if (_from != null)
{
_from.PositionChanged -= OnFromPositionChanged;
@@ -31,16 +36,31 @@ private set
}
}
- private InputConnectorViewModel _to;
+ [Browsable(false)]
+ private bool _isSelected;
+
+ public bool IsSelected
+ {
+ get { return _isSelected; }
+ set
+ {
+ _isSelected = value;
+ NotifyOfPropertyChange(() => IsSelected);
+ }
+ }
+
+
+ internal abstract InputConnectorViewModel _to { get; set; }
public InputConnectorViewModel To
{
get { return _to; }
set
{
+ if (value.Type != ConnectionType) throw new Exception();
if (_to != null)
{
_to.PositionChanged -= OnToPositionChanged;
- _to.Connection = null;
+ _to.Connections.Remove(this);
}
_to = value;
@@ -48,7 +68,7 @@ public InputConnectorViewModel To
if (_to != null)
{
_to.PositionChanged += OnToPositionChanged;
- _to.Connection = this;
+ _to.Connections.Add(this);
ToPosition = _to.Position;
}
@@ -67,6 +87,18 @@ public Point FromPosition
}
}
+ internal abstract Brush _color { get; set; }
+ public Brush Color
+ {
+ get { return _color; }
+ set
+ {
+ _color = value;
+ NotifyOfPropertyChange(() => Color);
+ }
+ }
+
+
private Point _toPosition;
public Point ToPosition
{
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs
new file mode 100644
index 00000000..a511609a
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connection/GenericConnectionViewModel.cs
@@ -0,0 +1,49 @@
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection
+{
+ abstract class GenericConnectionViewModel : ConnectionViewModel
+ {
+ public override Type ConnectionType { get; set; } = typeof(T);
+
+ GenericOutputConnectorViewModel from;
+ internal override OutputConnectorViewModel _from { get { return from; } set { from = (GenericOutputConnectorViewModel) value; _restoreLink(); } }
+
+ GenericInputConnectorViewModel to;
+ internal override InputConnectorViewModel _to { get { return to; } set {
+ to = (GenericInputConnectorViewModel)value; _restoreLink(); } }
+
+
+ private IDisposable _link;
+
+ //raise condition
+ void _restoreLink()
+ {
+ if(_link !=null) _link.Dispose();
+ if (_from == null || _to == null) return;
+ _link = from.output.LinkTo(to.target,new DataflowLinkOptions());
+ }
+
+ private void _exception(Exception x)
+ {
+
+ }
+
+ public GenericConnectionViewModel(GenericOutputConnectorViewModel from, GenericInputConnectorViewModel to) :base(from,to)
+ {
+ }
+
+ public GenericConnectionViewModel(GenericOutputConnectorViewModel from) : base(from)
+ {
+ }
+
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorDirection.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorDirection.cs
similarity index 100%
rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorDirection.cs
rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorDirection.cs
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs
similarity index 92%
rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs
rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs
index 6b12fd18..10e8b5d1 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ConnectorViewModel.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/ConnectorViewModel.cs
@@ -5,15 +5,13 @@
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
{
- public enum ConnectorDataType
- {
-
- }
public abstract class ConnectorViewModel : PropertyChangedBase
{
public event EventHandler PositionChanged;
+ public abstract Type Type { get; set; }
+
private readonly ElementViewModel _element;
public ElementViewModel Element
{
@@ -44,6 +42,7 @@ public Point Position
}
}
+ public abstract ConnectionViewModel GetNewConnection();
public abstract ConnectorDirection ConnectorDirection { get; }
protected ConnectorViewModel(ElementViewModel element, string name, Color color)
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs
new file mode 100644
index 00000000..d6b52704
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/BitmapSourceInputConnectorViewModel.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input
+{
+ class BitmapSourceInputConnectorViewModel : GenericInputConnectorViewModel
+ {
+ public BitmapSourceInputConnectorViewModel(ITargetBlock target, ElementViewModel element, string name, Color color) : base(target, element, name, color)
+ {
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs
new file mode 100644
index 00000000..668f6b58
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/GenericInputConnectorViewModel.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input
+{
+ abstract class GenericInputConnectorViewModel : InputConnectorViewModel
+ {
+ public ITargetBlock target;
+
+ public GenericInputConnectorViewModel(ITargetBlock target, ElementViewModel element, string name, Color color) : base( element, name, color)
+ {
+ this.target = target;
+ Type = typeof(T);
+ }
+ public override ConnectionViewModel GetNewConnection()
+ {
+ //throw new NotImplementedException();
+ return null;
+ }
+
+ public override Type Type { get; set; }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs
new file mode 100644
index 00000000..8bace996
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Input/InputConnectorViewModel.cs
@@ -0,0 +1,28 @@
+using Caliburn.Micro;
+using System;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
+{
+ public abstract class InputConnectorViewModel : ConnectorViewModel
+ {
+
+ public override ConnectorDirection ConnectorDirection
+ {
+ get { return ConnectorDirection.Input; }
+ }
+
+ private readonly BindableCollection _connections = new BindableCollection();
+ public IObservableCollection Connections
+ {
+ get { return _connections; }
+ }
+
+ public InputConnectorViewModel(ElementViewModel element, string name, Color color)
+ : base(element, name, color)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs
new file mode 100644
index 00000000..7dcd5569
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/BitmapSourceOutputConnectorViewModel.cs
@@ -0,0 +1,25 @@
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection;
+using Gridsum.DataflowEx;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output
+{
+ class BitmapSourceOutputConnectorViewModel : GenericOutputConnectorViewModel
+ {
+ public BitmapSourceOutputConnectorViewModel(ElementViewModel element, string name, Color color, ISourceBlock valueCallback) : base(element, name, color, valueCallback)
+ {
+ }
+
+ public override ConnectionViewModel GetNewConnection()
+ {
+ return new BitmapSourceConnection(this);
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs
new file mode 100644
index 00000000..448fb84f
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/GenericOutputConnectorViewModel.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output
+{
+ abstract class GenericOutputConnectorViewModel : OutputConnectorViewModel
+ {
+ public ISourceBlock output;
+
+ public GenericOutputConnectorViewModel(ElementViewModel element, string name, Color color, ISourceBlock valueCallback) : base(element, name, color)
+ {
+ output = valueCallback;
+ Type = typeof(T);
+ }
+
+ public override Type Type { get; set; }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs
similarity index 68%
rename from src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs
rename to src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs
index 45409d34..00a11646 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/OutputConnectorViewModel.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Connector/Output/OutputConnectorViewModel.cs
@@ -2,12 +2,12 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Caliburn.Micro;
+using System.Threading.Tasks.Dataflow;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
{
- public class OutputConnectorViewModel : ConnectorViewModel
+ public abstract class OutputConnectorViewModel : ConnectorViewModel
{
- private readonly Func _valueCallback;
public override ConnectorDirection ConnectorDirection
{
@@ -20,16 +20,17 @@ public IObservableCollection Connections
get { return _connections; }
}
- public BitmapSource Value
+ public OutputConnectorViewModel(ElementViewModel element, string name, Color color)
+ : base(element, name, color)
{
- get { return _valueCallback(); }
+ _connections = new BindableCollection();
}
- public OutputConnectorViewModel(ElementViewModel element, string name, Color color, Func valueCallback)
- : base(element, name, color)
+ internal ConnectionViewModel Connect(InputConnectorViewModel inputConnectorViewModel)
{
- _connections = new BindableCollection();
- _valueCallback = valueCallback;
+ var x = GetNewConnection();
+ x.To = inputConnectorViewModel;
+ return x;
}
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs
index 66fbe0f6..8a8feffb 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/ElementViewModel.cs
@@ -8,10 +8,13 @@
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
{
- public abstract class ElementViewModel : PropertyChangedBase
+ public interface IsSelectable
{
- public event EventHandler OutputChanged;
+ bool IsSelected { get; set; }
+ }
+ public abstract class ElementViewModel : PropertyChangedBase, IsSelectable
+ {
public const double PreviewSize = 100;
private double _x;
@@ -74,54 +77,36 @@ public IList InputConnectors
get { return _inputConnectors; }
}
- private OutputConnectorViewModel _outputConnector;
- public OutputConnectorViewModel OutputConnector
+ private readonly BindableCollection _outputConnectors;
+ public IList OutputConnectors
{
- get { return _outputConnector; }
- set
- {
- _outputConnector = value;
- NotifyOfPropertyChange(() => OutputConnector);
- }
+ get { return _outputConnectors; }
}
public IEnumerable AttachedConnections
{
get
{
- return _inputConnectors.Select(x => x.Connection)
- .Union(_outputConnector.Connections)
- .Where(x => x != null);
+ return _inputConnectors.SelectMany(x => x.Connections).Union(_outputConnectors.SelectMany(x => x.Connections));
}
}
protected ElementViewModel()
{
_inputConnectors = new BindableCollection();
+ _outputConnectors = new BindableCollection();
+
_name = GetType().Name;
}
- protected void AddInputConnector(string name, Color color)
+ protected void AddInputConnector(InputConnectorViewModel inputConnector)
{
- var inputConnector = new InputConnectorViewModel(this, name, color);
- inputConnector.SourceChanged += (sender, e) => OnInputConnectorConnectionChanged();
_inputConnectors.Add(inputConnector);
}
- protected void SetOutputConnector(string name, Color color, Func valueCallback)
- {
- OutputConnector = new OutputConnectorViewModel(this, name, color, valueCallback);
- }
-
- protected virtual void OnInputConnectorConnectionChanged()
- {
-
- }
-
- protected virtual void RaiseOutputChanged()
+ protected void AddOutputConnector(OutputConnectorViewModel outputConnector)
{
- EventHandler handler = OutputChanged;
- if (handler != null) handler(this, EventArgs.Empty);
+ OutputConnectors.Add(outputConnector);
}
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs
index 694eff16..6c2cea7e 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Add.cs
@@ -2,25 +2,34 @@
using System.Windows.Media.Effects;
using Gemini.Demo.Modules.FilterDesigner.ShaderEffects;
using Gemini.Modules.Toolbox;
+using System.Windows.Media.Imaging;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using System.Threading.Tasks.Dataflow;
+using Gridsum.DataflowEx;
+using System;
+using System.Threading.Tasks;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
{
[ToolboxItem(typeof(GraphViewModel), "Add", "Maths", "pack://application:,,,/Modules/FilterDesigner/Resources/action_add_16xLG.png")]
public class Add : ShaderEffectElement
{
- protected override Effect GetEffect()
+ public Add() : base()
{
- return new AddEffect
- {
- Input1 = new ImageBrush(InputConnectors[0].Value),
- Input2 = new ImageBrush(InputConnectors[1].Value)
- };
+
}
- public Add()
+
+ internal override DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2)
{
- AddInputConnector("Left", Colors.DarkSeaGreen);
- AddInputConnector("Right", Colors.DarkSeaGreen);
+ return new DrawingVisual()
+ {
+ Effect = new AddEffect
+ {
+ Input1 = new ImageBrush(Input1),
+ Input2 = new ImageBrush(Input2)
+ }
+ };
}
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs
new file mode 100644
index 00000000..9927e078
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/BitmapSourceElement.cs
@@ -0,0 +1,39 @@
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output;
+using Gridsum.DataflowEx;
+using System;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+using System.Windows;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
+{
+ public abstract class BitmapSourceElement : ElementViewModel
+ {
+ private BitmapSource _previewImage;
+
+ public override BitmapSource PreviewImage
+ {
+ get { return _previewImage; }
+ }
+
+ public Dataflow source { get; set; }
+
+ protected BitmapSourceElement()
+ {
+ source = new TransformBlock(X => displayImage(X),
+ new ExecutionDataflowBlockOptions() { TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()})
+ .ToDataflow(DataflowOptions.Default, Name);
+ AddOutputConnector(new BitmapSourceOutputConnectorViewModel(this, "Output", Colors.DarkSeaGreen, source.OutputBlock));
+ }
+
+ private BitmapSource displayImage(BitmapSource arg)
+ {
+ _previewImage = arg;
+ NotifyOfPropertyChange("PreviewImage");
+ return arg;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs
index 63bdb6ed..64643130 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ColorInput.cs
@@ -1,33 +1,51 @@
using System.Windows;
using System.Windows.Media;
using Gemini.Modules.Toolbox;
+using System.Threading.Tasks.Dataflow;
+using Gridsum.DataflowEx;
+using System.Windows.Media.Imaging;
+using System;
+using System.Threading.Tasks;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
{
[ToolboxItem(typeof(GraphViewModel), "Color", "Generators", "pack://application:,,,/Modules/FilterDesigner/Resources/color_swatch.png")]
- public class ColorInput : DynamicElement
+ public class ColorInput : BitmapSourceElement
{
private Color _color;
+
+ public ColorInput()
+ {
+ Color = Colors.Red;
+ }
+
+ private BitmapSource _transform(Color arg)
+ {
+ var dv = new DrawingVisual();
+ DrawingContext dc = dv.RenderOpen();
+ dc.DrawRectangle(new SolidColorBrush(arg), null, new Rect(0, 0, PreviewSize, PreviewSize));
+ dc.Close();
+ return Render(dv);
+ }
+ internal BitmapSource Render(DrawingVisual dv)
+ {
+ var rtb = new RenderTargetBitmap((int)PreviewSize, (int)PreviewSize, 96, 96, PixelFormats.Pbgra32);
+ rtb.Render(dv);
+
+ if (dv.Effect is IDisposable)
+ ((IDisposable)dv.Effect).Dispose();
+ rtb.Freeze();
+ return rtb;
+ }
public Color Color
{
get { return _color; }
set
{
_color = value;
- UpdatePreviewImage();
+ source.SendAsync(_transform(value));
NotifyOfPropertyChange(() => Color);
}
}
-
- public ColorInput()
- {
- Color = Colors.Red;
- UpdatePreviewImage();
- }
-
- protected override void Draw(DrawingContext drawingContext, Rect bounds)
- {
- drawingContext.DrawRectangle(new SolidColorBrush(Color), null, bounds);
- }
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs
deleted file mode 100644
index 4eef3aa9..00000000
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/DynamicElement.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-using System;
-using System.Windows;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
-namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
-{
- public abstract class DynamicElement : ElementViewModel
- {
- private BitmapSource _previewImage;
-
- public override BitmapSource PreviewImage
- {
- get { return _previewImage; }
- }
-
- protected DynamicElement()
- {
- SetOutputConnector("Output", Colors.DarkSeaGreen, () => PreviewImage);
- }
-
- protected virtual void PrepareDrawingVisual(DrawingVisual drawingVisual)
- {
-
- }
-
- protected abstract void Draw(DrawingContext drawingContext, Rect bounds);
-
- protected void UpdatePreviewImage()
- {
- var dv = new DrawingVisual();
- PrepareDrawingVisual(dv);
-
- DrawingContext dc = dv.RenderOpen();
- Draw(dc, new Rect(0, 0, PreviewSize, PreviewSize));
- dc.Close();
-
- var rtb = new RenderTargetBitmap((int) PreviewSize, (int) PreviewSize, 96, 96, PixelFormats.Pbgra32);
- rtb.Render(dv);
-
- if (dv.Effect is IDisposable)
- ((IDisposable) dv.Effect).Dispose();
-
- _previewImage = rtb;
- NotifyOfPropertyChange("PreviewImage");
-
- RaiseOutputChanged();
- }
-
- protected override void OnInputConnectorConnectionChanged()
- {
- UpdatePreviewImage();
- }
- }
-}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs
index 5ffd6c9b..ba89b205 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ImageSource.cs
@@ -1,12 +1,19 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using Gemini.Modules.Toolbox;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Output;
+using System.Threading.Tasks.Dataflow;
+using System;
+using Gridsum.DataflowEx;
+using System.Threading.Tasks;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
{
[ToolboxItem(typeof(GraphViewModel), "Image Source", "Generators", "pack://application:,,,/Modules/FilterDesigner/Resources/image.png")]
public class ImageSource : ElementViewModel
{
+ public Dataflow source;
+
private BitmapSource _bitmap;
public BitmapSource Bitmap
{
@@ -15,7 +22,8 @@ public BitmapSource Bitmap
{
_bitmap = value;
NotifyOfPropertyChange(() => PreviewImage);
- RaiseOutputChanged();
+ _bitmap.Freeze();
+ source.SendAsync(value);
}
}
@@ -26,7 +34,8 @@ public override BitmapSource PreviewImage
public ImageSource()
{
- SetOutputConnector("Output", Colors.DarkSeaGreen, () => Bitmap);
+ source = new DataBroadcaster(DataflowOptions.Default) { Name = this.Name };
+ AddOutputConnector(new BitmapSourceOutputConnectorViewModel(this, "Output", Colors.DarkSeaGreen, source.OutputBlock));
}
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs
index b65a611a..b90dd504 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/Multiply.cs
@@ -2,25 +2,34 @@
using System.Windows.Media.Effects;
using Gemini.Demo.Modules.FilterDesigner.ShaderEffects;
using Gemini.Modules.Toolbox;
+using System.Windows.Media.Imaging;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using Gridsum.DataflowEx;
+using System;
+using System.Threading.Tasks.Dataflow;
+using System.Threading.Tasks;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
{
[ToolboxItem(typeof(GraphViewModel), "Multiply", "Maths", "pack://application:,,,/Modules/FilterDesigner/Resources/active_x_16xLG.png")]
public class Multiply : ShaderEffectElement
{
- protected override Effect GetEffect()
+
+ public Multiply() : base()
{
- return new MultiplyEffect
- {
- Input1 = new ImageBrush(InputConnectors[0].Value),
- Input2 = new ImageBrush(InputConnectors[1].Value)
- };
+
}
- public Multiply()
+ internal override DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2)
{
- AddInputConnector("Left", Colors.DarkSeaGreen);
- AddInputConnector("Right", Colors.DarkSeaGreen);
+ return new DrawingVisual
+ {
+ Effect = new MultiplyEffect
+ {
+ Input1 = new ImageBrush(Input1),
+ Input2 = new ImageBrush(Input2)
+ }
+ };
}
}
}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs
index 562f7bbf..f2e1991a 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/Elements/ShaderEffectElement.cs
@@ -1,23 +1,49 @@
-using System.Windows;
+using Gridsum.DataflowEx;
+using System.Threading.Tasks.Dataflow;
+using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Effects;
+using System.Windows.Media.Imaging;
+using System;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connector.Input;
+using Common.Logging;
+using System.Threading.Tasks;
+using Common.Logging.Simple;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements
{
- public abstract class ShaderEffectElement : DynamicElement
+ public abstract class ShaderEffectElement : BitmapSourceElement
{
- protected override void PrepareDrawingVisual(DrawingVisual drawingVisual)
+ public JoinAny inputJoin = new JoinAny();
+ public Dataflow<(BitmapSource, BitmapSource), BitmapSource> shaderTransformer { get; set; }
+
+
+ public ShaderEffectElement()
{
- drawingVisual.Effect = GetEffect();
+ shaderTransformer = new TransformBlock<(BitmapSource, BitmapSource), BitmapSource>(x => UpdatePreviewImage(x.Item1, x.Item2))
+ .ToDataflow(DataflowOptions.Default, "Shader");
+ AddInputConnector(new BitmapSourceInputConnectorViewModel(inputJoin.Target1.InputBlock, this, "Left", Colors.DarkSeaGreen));
+ AddInputConnector(new BitmapSourceInputConnectorViewModel(inputJoin.Target2.InputBlock, this, "Right", Colors.DarkSeaGreen));
+ inputJoin.source.LinkTo(shaderTransformer);
+ shaderTransformer.LinkTo(source);
}
- protected override void Draw(DrawingContext drawingContext, Rect bounds)
+ internal abstract DrawingVisual GetEffect(BitmapSource Input1, BitmapSource Input2);
+
+ internal BitmapSource UpdatePreviewImage(BitmapSource Input1, BitmapSource Input2)
{
- drawingContext.DrawRectangle(
- new SolidColorBrush(Colors.Transparent), null,
- bounds);
+ var x = GetEffect(Input1, Input2);
+ DrawingContext dc = x.RenderOpen();
+ dc.DrawRectangle(
+ new SolidColorBrush(Colors.Transparent), null,
+ new Rect(0, 0, PreviewSize, PreviewSize));
+ dc.Close();
+ var rtb = new RenderTargetBitmap((int)PreviewSize, (int)PreviewSize, 96, 96, PixelFormats.Pbgra32);
+ rtb.Render(x);
+ if (x.Effect is IDisposable)
+ ((IDisposable)x.Effect).Dispose();
+ rtb.Freeze();
+ return (BitmapSource)rtb;
}
-
- protected abstract Effect GetEffect();
}
-}
\ No newline at end of file
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs
index 361f3855..96bc3c53 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/GraphViewModel.cs
@@ -10,6 +10,9 @@
using Gemini.Framework;
using Gemini.Modules.Inspector;
using ImageSource = Gemini.Demo.Modules.FilterDesigner.ViewModels.Elements.ImageSource;
+using System.Windows.Media.Imaging;
+using Gemini.Demo.Modules.FilterDesigner.ViewModels.Connection;
+using System;
namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
{
@@ -31,9 +34,9 @@ public IObservableCollection Connections
get { return _connections; }
}
- public IEnumerable SelectedElements
+ public IEnumerable SelectedElements
{
- get { return _elements.Where(x => x.IsSelected); }
+ get { return _elements.Where(x => x.IsSelected).Concat(_connections.Where(x=>x.IsSelected)); }
}
[ImportingConstructor]
@@ -46,7 +49,7 @@ public GraphViewModel(IInspectorTool inspectorTool)
_inspectorTool = inspectorTool;
- var element1 = AddElement(100, 50);
+ ImageSource element1 = AddElement(100, 50);
element1.Bitmap = BitmapUtility.CreateFromBytes(DesignTimeImages.Desert);
var element2 = AddElement(100, 300);
@@ -54,13 +57,8 @@ public GraphViewModel(IInspectorTool inspectorTool)
var element3 = AddElement(400, 250);
- Connections.Add(new ConnectionViewModel(
- element1.OutputConnector,
- element3.InputConnectors[0]));
-
- Connections.Add(new ConnectionViewModel(
- element2.OutputConnector,
- element3.InputConnectors[1]));
+ Connections.Add(element1.OutputConnectors[0].Connect(element3.InputConnectors[0]));
+ Connections.Add(element2.OutputConnectors[0].Connect(element3.InputConnectors[1]));
element1.IsSelected = true;
}
@@ -77,11 +75,11 @@ public ConnectionViewModel OnConnectionDragStarted(ConnectorViewModel sourceConn
{
if (!(sourceConnector is OutputConnectorViewModel))
return null;
+ var tt = sourceConnector.Type;
- var connection = new ConnectionViewModel((OutputConnectorViewModel) sourceConnector)
- {
- ToPosition = currentDragPoint
- };
+ var connection = sourceConnector.GetNewConnection();
+ connection.ToPosition = currentDragPoint;
+
Connections.Add(connection);
@@ -91,7 +89,7 @@ public ConnectionViewModel OnConnectionDragStarted(ConnectorViewModel sourceConn
public void OnConnectionDragging(Point currentDragPoint, ConnectionViewModel connection)
{
// If current drag point is close to an input connector, show its snapped position.
- var nearbyConnector = FindNearbyInputConnector(currentDragPoint);
+ var nearbyConnector = FindNearbyInputConnector(currentDragPoint, connection.ConnectionType);
connection.ToPosition = (nearbyConnector != null)
? nearbyConnector.Position
: currentDragPoint;
@@ -99,7 +97,7 @@ public void OnConnectionDragging(Point currentDragPoint, ConnectionViewModel con
public void OnConnectionDragCompleted(Point currentDragPoint, ConnectionViewModel newConnection, ConnectorViewModel sourceConnector)
{
- var nearbyConnector = FindNearbyInputConnector(currentDragPoint);
+ var nearbyConnector = FindNearbyInputConnector(currentDragPoint, newConnection.ConnectionType);
if (nearbyConnector == null || sourceConnector.Element == nearbyConnector.Element)
{
@@ -107,17 +105,13 @@ public void OnConnectionDragCompleted(Point currentDragPoint, ConnectionViewMode
return;
}
- var existingConnection = nearbyConnector.Connection;
- if (existingConnection != null)
- Connections.Remove(existingConnection);
-
newConnection.To = nearbyConnector;
}
- private InputConnectorViewModel FindNearbyInputConnector(Point mousePosition)
+ private InputConnectorViewModel FindNearbyInputConnector(Point mousePosition, Type t)
{
return Elements.SelectMany(x => x.InputConnectors)
- .FirstOrDefault(x => AreClose(x.Position, mousePosition, 10));
+ .FirstOrDefault(x => x.Type == t && AreClose(x.Position, mousePosition, 10));
}
private static bool AreClose(Point point1, Point point2, double distance)
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs
deleted file mode 100644
index a8ab77fc..00000000
--- a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/InputConnectorViewModel.cs
+++ /dev/null
@@ -1,61 +0,0 @@
-using System;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-
-namespace Gemini.Demo.Modules.FilterDesigner.ViewModels
-{
- public class InputConnectorViewModel : ConnectorViewModel
- {
- public event EventHandler SourceChanged;
-
- public override ConnectorDirection ConnectorDirection
- {
- get { return ConnectorDirection.Input; }
- }
-
- private ConnectionViewModel _connection;
- public ConnectionViewModel Connection
- {
- get { return _connection; }
- set
- {
- if (_connection != null)
- _connection.From.Element.OutputChanged -= OnSourceElementOutputChanged;
- _connection = value;
- if (_connection != null)
- _connection.From.Element.OutputChanged += OnSourceElementOutputChanged;
- RaiseSourceChanged();
- NotifyOfPropertyChange(() => Connection);
- }
- }
-
- private void OnSourceElementOutputChanged(object sender, EventArgs e)
- {
- RaiseSourceChanged();
- }
-
- public BitmapSource Value
- {
- get
- {
- if (Connection == null || Connection.From == null)
- return null;
-
- return Connection.From.Value;
- }
- }
-
- public InputConnectorViewModel(ElementViewModel element, string name, Color color)
- : base(element, name, color)
- {
-
- }
-
- private void RaiseSourceChanged()
- {
- var handler = SourceChanged;
- if (handler!= null)
- handler(this, EventArgs.Empty);
- }
- }
-}
\ No newline at end of file
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs
new file mode 100644
index 00000000..bcdb88c1
--- /dev/null
+++ b/src/Gemini.Demo/Modules/FilterDesigner/ViewModels/JoinAnyBlock.cs
@@ -0,0 +1,41 @@
+using Gridsum.DataflowEx;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Tasks.Dataflow;
+
+namespace Gemini.Demo.Modules.FilterDesigner
+{
+ public class JoinAny
+ {
+ public Task Completion => throw new NotImplementedException();
+ public Dataflow Target1;
+ public Dataflow Target2;
+ public Dataflow<(T1, T2), (T1, T2)> source;
+ public bool first;
+ T1 I1;
+ T2 I2;
+ public JoinAny()
+ {
+ Target1 = new BufferBlock(new DataflowBlockOptions()).ToDataflow();
+ Target2 = new BufferBlock(new DataflowBlockOptions()).ToDataflow();
+ Target1.OutputBlock.AsObservable().Subscribe(x => _in1(x));
+ Target2.OutputBlock.AsObservable().Subscribe(x => _in2(x));
+
+ source = new BufferBlock<(T1, T2)>().ToDataflow();
+
+ }
+ private void _in2(T2 x)
+ {
+ I2 = x;
+ if (I1 != null) source.SendAsync((I1, I2));
+ }
+ private void _in1(T1 x)
+ {
+ I1 = x;
+ if (I2 != null) source.SendAsync((I1, I2));
+ }
+ }
+}
diff --git a/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml b/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml
index 28c403ff..c67b9f33 100644
--- a/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml
+++ b/src/Gemini.Demo/Modules/FilterDesigner/Views/GraphView.xaml
@@ -8,6 +8,7 @@
xmlns:vm="clr-namespace:Gemini.Demo.Modules.FilterDesigner.ViewModels"
mc:Ignorable="d"
d:DesignHeight="500" d:DesignWidth="700"
+ xmlns:dd="clr-namespace:Gemini.Demo.Modules.FilterDesigner.Design"
d:DataContext="{d:DesignInstance dd:DesignTimeGraphViewModel, IsDesignTimeCreatable=True}"
Background="WhiteSmoke" Focusable="True">
@@ -39,14 +40,14 @@
-
+