Refactor Equation to be treated as a model and update Key Graph Features (#791)

* refactor code

* update KGF

* Rename some functions

* Undo comment out of proj file

* Pr feedback
This commit is contained in:
Pepe Rivera
2019-11-20 14:28:32 -08:00
committed by GitHub
parent 9ee2f8a293
commit 288a90e0fe
16 changed files with 215 additions and 764 deletions

View File

@@ -23,9 +23,6 @@ namespace GraphControl
DependencyProperty ^ Equation::s_lineColorProperty;
static constexpr auto s_propertyName_LineColor = L"LineColor";
DependencyProperty ^ Equation::s_isAnalysisUpdatedProperty;
static constexpr auto s_propertyName_IsAnalysisUpdated = L"IsAnalysisUpdated";
DependencyProperty ^ Equation::s_xInterceptProperty;
static constexpr auto s_propertyName_XIntercept = L"XIntercept";
@@ -78,7 +75,6 @@ namespace GraphControl
{
String ^ Expression = StringReference(s_propertyName_Expression);
String ^ LineColor = StringReference(s_propertyName_LineColor);
String ^ IsAnalysisUpdated = StringReference(s_propertyName_IsAnalysisUpdated);
String ^ XIntercept = StringReference(s_propertyName_XIntercept);
String ^ YIntercept = StringReference(s_propertyName_YIntercept);
String ^ Parity = StringReference(s_propertyName_Parity);
@@ -120,15 +116,6 @@ namespace GraphControl
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
}
if (!s_isAnalysisUpdatedProperty)
{
s_isAnalysisUpdatedProperty = DependencyProperty::Register(
EquationProperties::IsAnalysisUpdated,
bool ::typeid,
Equation::typeid,
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
}
if (!s_xInterceptProperty)
{
s_xInterceptProperty = DependencyProperty::Register(
@@ -286,10 +273,6 @@ namespace GraphControl
{
propertyName = EquationProperties::LineColor;
}
else if (args->Property == s_isAnalysisUpdatedProperty)
{
propertyName = EquationProperties::IsAnalysisUpdated;
}
else if (args->Property == s_xInterceptProperty)
{
propertyName = EquationProperties::XIntercept;

View File

@@ -14,7 +14,7 @@ namespace GraphControl
ref class Equation;
delegate void PropertyChangedEventHandler(Equation ^ sender, Platform::String ^ propertyName);
[Windows::UI::Xaml::Data::Bindable] public ref class Equation sealed : public Windows::UI::Xaml::FrameworkElement
[Windows::UI::Xaml::Data::Bindable] public ref class Equation sealed : public Windows::UI::Xaml::DependencyObject
{
public:
@@ -70,26 +70,7 @@ namespace GraphControl
#pragma region Key Graph Features
#pragma region bool IsAnalysisUpdated DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ IsAnalysisUpdatedProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
{
return s_isAnalysisUpdatedProperty;
}
}
property bool IsAnalysisUpdated
{
bool get()
{
return static_cast<bool>(GetValue(s_isAnalysisUpdatedProperty));
}
void set(bool value)
{
SetValue(s_isAnalysisUpdatedProperty, value);
}
}
#pragma endregion
#pragma region Platform::String ^ XIntercept DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ XInterceptProperty
{
@@ -441,7 +422,6 @@ namespace GraphControl
private:
static Windows::UI::Xaml::DependencyProperty ^ s_expressionProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_lineColorProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_isAnalysisUpdatedProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_xInterceptProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_yInterceptProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_parityProperty;

View File

@@ -30,9 +30,7 @@ namespace
constexpr auto s_defaultStyleKey = L"GraphControl.Grapher";
constexpr auto s_templateKey_SwapChainPanel = L"GraphSurface";
constexpr auto s_propertyName_EquationTemplate = L"EquationTemplate";
constexpr auto s_propertyName_Equations = L"Equations";
constexpr auto s_propertyName_EquationsSource = L"EquationsSource";
constexpr auto s_propertyName_Variables = L"Variables";
constexpr auto s_propertyName_ForceProportionalAxes = L"ForceProportionalAxes";
@@ -54,9 +52,7 @@ namespace
namespace GraphControl
{
DependencyProperty ^ Grapher::s_equationTemplateProperty;
DependencyProperty ^ Grapher::s_equationsProperty;
DependencyProperty ^ Grapher::s_equationsSourceProperty;
DependencyProperty ^ Grapher::s_variablesProperty;
DependencyProperty ^ Grapher::s_forceProportionalAxesTemplateProperty;
@@ -160,24 +156,6 @@ namespace GraphControl
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
}
if (!s_equationsSourceProperty)
{
s_equationsSourceProperty = DependencyProperty::Register(
StringReference(s_propertyName_EquationsSource),
Object::typeid,
Grapher::typeid,
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
}
if (!s_equationTemplateProperty)
{
s_equationTemplateProperty = DependencyProperty::Register(
StringReference(s_propertyName_EquationTemplate),
DataTemplate::typeid,
Grapher::typeid,
ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
}
if (!s_variablesProperty)
{
s_variablesProperty = DependencyProperty::Register(
@@ -206,14 +184,6 @@ namespace GraphControl
{
self->OnEquationsChanged(args);
}
else if (args->Property == EquationsSourceProperty)
{
self->OnEquationsSourceChanged(args);
}
else if (args->Property == EquationTemplateProperty)
{
self->OnEquationTemplateChanged(args);
}
else if (args->Property == ForceProportionalAxesTemplateProperty)
{
self->OnForceProportionalAxesChanged(args);
@@ -230,95 +200,10 @@ namespace GraphControl
}
}
void Grapher::OnEquationTemplateChanged(DependencyPropertyChangedEventArgs ^ args)
{
SyncEquationsWithItemsSource();
}
void Grapher::OnEquationsSourceChanged(DependencyPropertyChangedEventArgs ^ args)
{
if (m_dataSource && m_tokenDataSourceChanged.Value != 0)
{
m_dataSource->DataSourceChanged -= m_tokenDataSourceChanged;
}
m_dataSource = args->NewValue ? ref new InspectingDataSource(args->NewValue) : nullptr;
if (m_dataSource)
{
m_tokenDataSourceChanged = m_dataSource->DataSourceChanged +=
ref new TypedEventHandler<InspectingDataSource ^, DataSourceChangedEventArgs>(this, &Grapher::OnDataSourceChanged);
}
SyncEquationsWithItemsSource();
}
void Grapher::OnDataSourceChanged(InspectingDataSource ^ sender, DataSourceChangedEventArgs args)
{
switch (args.Action)
{
case DataSourceChangedAction::Insert:
OnItemsAdded(args.NewStartingIndex, args.NewItemsCount);
break;
case DataSourceChangedAction::Remove:
OnItemsRemoved(args.OldStartingIndex, args.OldItemsCount);
break;
case DataSourceChangedAction::Reset:
SyncEquationsWithItemsSource();
break;
case DataSourceChangedAction::Replace:
OnItemsRemoved(args.OldStartingIndex, args.OldItemsCount);
OnItemsAdded(args.NewStartingIndex, args.NewItemsCount);
break;
}
}
void Grapher::OnItemsAdded(int index, int count)
{
for (int i = index + count - 1; i >= index; i--)
{
auto eq = safe_cast<Equation ^>(EquationTemplate->LoadContent());
eq->DataContext = m_dataSource->GetAt(i);
Equations->InsertAt(index, eq);
}
}
void Grapher::OnItemsRemoved(int index, int count)
{
for (int i = 0; i < count; i++)
{
Equations->RemoveAt(index);
}
}
void Grapher::SyncEquationsWithItemsSource()
{
Equations->Clear();
if (m_dataSource)
{
auto size = m_dataSource->GetSize();
for (auto i = 0u; i < size; i++)
{
auto eq = safe_cast<Equation ^>(EquationTemplate->LoadContent());
eq->DataContext = m_dataSource->GetAt(i);
Equations->Append(eq);
}
}
}
void Grapher::OnEquationsChanged(DependencyPropertyChangedEventArgs ^ args)
{
if (auto older = static_cast<EquationCollection ^>(args->OldValue))
{
if (m_tokenEquationsChanged.Value != 0)
{
older->VectorChanged -= m_tokenEquationsChanged;
m_tokenEquationsChanged.Value = 0;
}
if (m_tokenEquationChanged.Value != 0)
{
older->EquationChanged -= m_tokenEquationChanged;
@@ -334,8 +219,6 @@ namespace GraphControl
if (auto newer = static_cast<EquationCollection ^>(args->NewValue))
{
m_tokenEquationsChanged = newer->VectorChanged += ref new VectorChangedEventHandler<Equation ^>(this, &Grapher::OnEquationsVectorChanged);
m_tokenEquationChanged = newer->EquationChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationChanged);
m_tokenEquationStyleChanged = newer->EquationStyleChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationStyleChanged);
@@ -344,22 +227,6 @@ namespace GraphControl
UpdateGraph();
}
void Grapher::OnEquationsVectorChanged(IObservableVector<Equation ^> ^ sender, IVectorChangedEventArgs ^ event)
{
if (event->CollectionChange == ::CollectionChange::ItemInserted || event->CollectionChange == ::CollectionChange::ItemChanged)
{
auto eq = sender->GetAt(event->Index);
// Don't update the graph unless the equations being added/modified is valid.
if (eq->Expression->IsEmpty())
{
return;
}
}
UpdateGraph();
}
void Grapher::OnEquationChanged()
{
UpdateGraph();
@@ -378,6 +245,56 @@ namespace GraphControl
}
}
void Grapher::PlotGraph()
{
UpdateGraph();
}
void Grapher::AnalyzeEquation(Equation ^ equation)
{
if (auto graph = GetGraph(equation))
{
if (auto analyzer = graph->GetAnalyzer())
{
if (analyzer->CanFunctionAnalysisBePerformed())
{
if (S_OK == analyzer->PerformFunctionAnalysis((Graphing::Analyzer::NativeAnalysisType)Graphing::Analyzer::PerformAnalysisType::PerformAnalysisType_All))
{
Graphing::IGraphFunctionAnalysisData functionAnalysisData = m_solver->Analyze(analyzer.get());
{
equation->XIntercept = ref new String(functionAnalysisData.Zeros.c_str());
equation->YIntercept = ref new String(functionAnalysisData.YIntercept.c_str());
equation->Domain = ref new String(functionAnalysisData.Domain.c_str());
equation->Range = ref new String(functionAnalysisData.Range.c_str());
equation->Parity = functionAnalysisData.Parity;
equation->PeriodicityDirection = functionAnalysisData.PeriodicityDirection;
equation->PeriodicityExpression = ref new String(functionAnalysisData.PeriodicityExpression.c_str());
equation->Minima = ConvertWStringVector(functionAnalysisData.Minima);
equation->Maxima = ConvertWStringVector(functionAnalysisData.Maxima);
equation->InflectionPoints = ConvertWStringVector(functionAnalysisData.InflectionPoints);
equation->Monotonicity = ConvertWStringIntMap(functionAnalysisData.MonotoneIntervals);
equation->VerticalAsymptotes = ConvertWStringVector(functionAnalysisData.VerticalAsymptotes);
equation->HorizontalAsymptotes = ConvertWStringVector(functionAnalysisData.HorizontalAsymptotes);
equation->ObliqueAsymptotes = ConvertWStringVector(functionAnalysisData.ObliqueAsymptotes);
equation->TooComplexFeatures = functionAnalysisData.TooComplexFeatures;
equation->AnalysisError = CalculatorApp::AnalysisErrorType::NoError;
return;
}
}
}
else
{
equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisNotSupported;
return;
}
}
}
equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed;
}
void Grapher::UpdateGraph()
{
if (m_renderMain && m_graph != nullptr)
@@ -414,7 +331,6 @@ namespace GraphControl
m_renderMain->Graph = m_graph;
UpdateVariables();
UpdateKeyGraphFeatures();
}
}
}
@@ -428,7 +344,6 @@ namespace GraphControl
m_renderMain->Graph = m_graph;
UpdateVariables();
UpdateKeyGraphFeatures();
}
}
}
@@ -467,59 +382,6 @@ namespace GraphControl
return nullptr;
}
void Grapher::UpdateKeyGraphFeatures()
{
auto equations = GetValidEquations();
for (auto equation : equations)
{
equation->IsAnalysisUpdated = false;
if (auto graph = GetGraph(equation))
{
if (auto analyzer = graph->GetAnalyzer())
{
if (analyzer->CanFunctionAnalysisBePerformed())
{
if (S_OK
== analyzer->PerformFunctionAnalysis(
(Graphing::Analyzer::NativeAnalysisType)Graphing::Analyzer::PerformAnalysisType::PerformAnalysisType_All))
{
Graphing::IGraphFunctionAnalysisData functionAnalysisData = m_solver->Analyze(analyzer.get());
{
equation->XIntercept = ref new String(functionAnalysisData.Zeros.c_str());
equation->YIntercept = ref new String(functionAnalysisData.YIntercept.c_str());
equation->Domain = ref new String(functionAnalysisData.Domain.c_str());
equation->Range = ref new String(functionAnalysisData.Range.c_str());
equation->Parity = functionAnalysisData.Parity;
equation->PeriodicityDirection = functionAnalysisData.PeriodicityDirection;
equation->PeriodicityExpression = ref new String(functionAnalysisData.PeriodicityExpression.c_str());
equation->Minima = ConvertWStringVector(functionAnalysisData.Minima);
equation->Maxima = ConvertWStringVector(functionAnalysisData.Maxima);
equation->InflectionPoints = ConvertWStringVector(functionAnalysisData.InflectionPoints);
equation->Monotonicity = ConvertWStringIntMap(functionAnalysisData.MonotoneIntervals);
equation->VerticalAsymptotes = ConvertWStringVector(functionAnalysisData.VerticalAsymptotes);
equation->HorizontalAsymptotes = ConvertWStringVector(functionAnalysisData.HorizontalAsymptotes);
equation->ObliqueAsymptotes = ConvertWStringVector(functionAnalysisData.ObliqueAsymptotes);
equation->TooComplexFeatures = functionAnalysisData.TooComplexFeatures;
equation->AnalysisError = CalculatorApp::AnalysisErrorType::NoError;
equation->IsAnalysisUpdated = true;
continue;
}
}
}
else
{
equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisNotSupported;
equation->IsAnalysisUpdated = true;
continue;
}
}
}
equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed;
equation->IsAnalysisUpdated = true;
}
}
IObservableVector<String ^> ^ Grapher::ConvertWStringVector(vector<wstring> inVector)
{
Vector<String ^> ^ outVector = ref new Vector<String ^>();

View File

@@ -3,7 +3,6 @@
#pragma once
#include "InspectingDataSource.h"
#include "DirectX/RenderMain.h"
#include "Equation.h"
#include "EquationCollection.h"
@@ -30,50 +29,6 @@ public
static void RegisterDependencyProperties();
#pragma region Windows::UI::Xaml::DataTemplate ^ EquationTemplate DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationTemplateProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
{
return s_equationTemplateProperty;
}
}
property Windows::UI::Xaml::DataTemplate^ EquationTemplate
{
Windows::UI::Xaml::DataTemplate^ get()
{
return static_cast<Windows::UI::Xaml::DataTemplate^>(GetValue(s_equationTemplateProperty));
}
void set(Windows::UI::Xaml::DataTemplate^ value)
{
SetValue(s_equationTemplateProperty, value);
}
}
#pragma endregion
#pragma region Platform::Object ^ EquationsSource DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationsSourceProperty
{
Windows::UI::Xaml::DependencyProperty^ get()
{
return s_equationsSourceProperty;
}
}
property Platform::Object^ EquationsSource
{
Platform::Object^ get()
{
return GetValue(s_equationsSourceProperty);
}
void set(Platform::Object^ value)
{
SetValue(s_equationsSourceProperty, value);
}
}
#pragma endregion
#pragma region GraphControl::EquationCollection ^ Equations DependencyProperty
static property Windows::UI::Xaml::DependencyProperty^ EquationsProperty
{
@@ -191,6 +146,8 @@ public
event Windows::Foundation::EventHandler<Windows::Foundation::Collections::IMap<Platform::String ^, double> ^> ^ VariablesUpdated;
void SetVariable(Platform::String ^ variableName, double newValue);
Platform::String ^ ConvertToLinear(Platform::String ^ mmlString);
void PlotGraph();
void AnalyzeEquation(GraphControl::Equation ^ equation);
protected:
#pragma region Control Overrides
@@ -213,15 +170,7 @@ public
static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyProperty ^ p);
void OnEquationTemplateChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnEquationsSourceChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnDataSourceChanged(GraphControl::InspectingDataSource ^ sender, GraphControl::DataSourceChangedEventArgs args);
void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnEquationsVectorChanged(
Windows::Foundation::Collections::IObservableVector<GraphControl::Equation ^> ^ sender,
Windows::Foundation::Collections::IVectorChangedEventArgs ^ event);
void OnEquationChanged();
void OnEquationStyleChanged();
@@ -231,16 +180,11 @@ public
void SetGraphArgs();
std::shared_ptr<Graphing::IGraph> GetGraph(GraphControl::Equation ^ equation);
void UpdateVariables();
void UpdateKeyGraphFeatures();
void OnForceProportionalAxesChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
void OnBackgroundColorChanged(const Windows::UI::Color& color);
void SyncEquationsWithItemsSource();
void OnItemsAdded(int index, int count);
void OnItemsRemoved(int index, int count);
void ScaleRange(double centerX, double centerY, double scale);
void OnCoreKeyDown(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::KeyEventArgs ^ e);
@@ -259,7 +203,6 @@ public
static Windows::UI::Xaml::DependencyProperty ^ s_equationTemplateProperty;
static Windows::UI::Xaml::DependencyProperty ^ s_equationsSourceProperty;
InspectingDataSource ^ m_dataSource;
Windows::Foundation::EventRegistrationToken m_tokenDataSourceChanged;
static Windows::UI::Xaml::DependencyProperty ^ s_equationsProperty;

View File

@@ -1,245 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#include "pch.h"
#include "InspectingDataSource.h"
using namespace Platform;
using namespace Platform::Collections;
using namespace std;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI::Xaml::Interop;
namespace winrt
{
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::UI::Xaml::Interop;
}
namespace GraphControl
{
InspectingDataSource::InspectingDataSource(Object^ source)
{
if (!source)
{
throw ref new InvalidArgumentException(L"Argument 'source' is null.");
}
auto inspectable = from_cx<winrt::IInspectable>(source);
if (auto vector = inspectable.try_as<winrt::IVector<winrt::IInspectable>>())
{
m_vector = vector;
ListenToCollectionChanges();
}
else if (auto bindableVector = inspectable.try_as<winrt::IBindableVector>())
{
// The bindable interop interface are abi compatible with the corresponding
// WinRT interfaces.
m_vector = reinterpret_cast<const winrt::IVector<winrt::IInspectable>&>(bindableVector);
ListenToCollectionChanges();
}
else if (auto iterable = inspectable.try_as<winrt::IIterable<winrt::IInspectable>>())
{
m_vector = WrapIterable(iterable);
}
else if (auto bindableIterable = inspectable.try_as<winrt::IBindableIterable>())
{
m_vector = WrapIterable(reinterpret_cast<const winrt::IIterable<winrt::IInspectable> &>(bindableIterable));
}
else
{
throw ref new InvalidArgumentException(L"Argument 'source' is not a supported vector.");
}
}
InspectingDataSource::~InspectingDataSource()
{
UnlistenToCollectionChanges();
}
unsigned int InspectingDataSource::GetSize()
{
return m_vector.Size();
}
Object^ InspectingDataSource::GetAt(unsigned int index)
{
return to_cx<Object>(m_vector.GetAt(index));
}
optional<unsigned int> InspectingDataSource::IndexOf(Object^ value)
{
if ((m_vector != nullptr) && value)
{
uint32_t v;
auto inspectable = from_cx<winrt::IInspectable>(value);
if (m_vector.IndexOf(inspectable, v))
{
return v;
}
}
return nullopt;
}
winrt::IVector<winrt::IInspectable> InspectingDataSource::WrapIterable(const winrt::IIterable<winrt::IInspectable>& iterable)
{
auto vector = winrt::single_threaded_vector<winrt::IInspectable>();
auto iterator = iterable.First();
while (iterator.HasCurrent())
{
vector.Append(iterator.Current());
iterator.MoveNext();
}
return vector;
}
void InspectingDataSource::UnlistenToCollectionChanges()
{
if (m_notifyCollectionChanged)
{
m_notifyCollectionChanged.CollectionChanged(m_eventToken);
}
else if (m_observableVector)
{
m_observableVector.VectorChanged(m_eventToken);
}
else if (m_bindableObservableVector)
{
m_bindableObservableVector.VectorChanged(m_eventToken);
}
}
void InspectingDataSource::ListenToCollectionChanges()
{
assert(m_vector);
if (auto incc = m_vector.try_as<winrt::INotifyCollectionChanged>())
{
m_eventToken = incc.CollectionChanged([this](
const winrt::IInspectable& sender,
const winrt::NotifyCollectionChangedEventArgs& e)
{
OnCollectionChanged(sender, e);
});
m_notifyCollectionChanged = incc;
}
else if (auto observableVector = m_vector.try_as<winrt::IObservableVector<winrt::IInspectable>>())
{
m_eventToken = observableVector.VectorChanged([this](
const winrt::IObservableVector<winrt::IInspectable>& sender,
const winrt::IVectorChangedEventArgs& e)
{
OnVectorChanged(sender, e);
});
m_observableVector = observableVector;
}
else if (auto bindableObservableVector = m_vector.try_as<winrt::IBindableObservableVector>())
{
m_eventToken = bindableObservableVector.VectorChanged([this](
winrt::IBindableObservableVector const& vector,
winrt::IInspectable const& e)
{
OnBindableVectorChanged(vector, e);
});
m_bindableObservableVector = bindableObservableVector;
}
}
void InspectingDataSource::OnCollectionChanged(
const winrt::IInspectable& /*sender*/,
const winrt::NotifyCollectionChangedEventArgs& e)
{
DataSourceChangedAction action;
switch (e.Action())
{
case winrt::NotifyCollectionChangedAction::Add:
action = DataSourceChangedAction::Insert;
break;
case winrt::NotifyCollectionChangedAction::Remove:
action = DataSourceChangedAction::Remove;
break;
case winrt::NotifyCollectionChangedAction::Replace:
action = DataSourceChangedAction::Replace;
break;
case winrt::NotifyCollectionChangedAction::Reset:
action = DataSourceChangedAction::Reset;
break;
case winrt::NotifyCollectionChangedAction::Move:
throw ref new Exception(E_FAIL, L"Move operations are not supported. Use a combination of Add and Remove instead.");
break;
default:
assert(false);
break;
}
const auto& newItems = e.NewItems();
const auto& oldItems = e.OldItems();
DataSourceChanged(this, DataSourceChangedEventArgs{
action,
e.OldStartingIndex(),
oldItems ? static_cast<int>(oldItems.Size()) : 0,
e.NewStartingIndex(),
newItems ? static_cast<int>(newItems.Size()) : 0 });
}
void InspectingDataSource::OnVectorChanged(
const winrt::Collections::IObservableVector<winrt::IInspectable>& /*sender*/,
const winrt::Collections::IVectorChangedEventArgs& e)
{
DataSourceChangedAction action;
int oldStartingIndex = -1;
int oldItemsCount = 0;
int newStartingIndex = -1;
int newItemsCount = 0;
// Note that the event args' Index property should NOT be accessed
// in the Reset case, as the property accessor will throw an exception.
switch (e.CollectionChange())
{
case winrt::CollectionChange::ItemInserted:
action = DataSourceChangedAction::Insert;
newStartingIndex = e.Index();
newItemsCount = 1;
break;
case winrt::CollectionChange::ItemRemoved:
action = DataSourceChangedAction::Remove;
oldStartingIndex = e.Index();
oldItemsCount = 1;
break;
case winrt::CollectionChange::ItemChanged:
action = DataSourceChangedAction::Replace;
oldStartingIndex = e.Index();
oldItemsCount = 1;
newStartingIndex = e.Index();
newItemsCount = 1;
break;
case winrt::CollectionChange::Reset:
action = DataSourceChangedAction::Reset;
break;
default:
assert(false);
break;
}
DataSourceChanged(this, DataSourceChangedEventArgs{
action,
oldStartingIndex,
oldItemsCount,
newStartingIndex,
newItemsCount });
}
void InspectingDataSource::OnBindableVectorChanged(
winrt::IBindableObservableVector const& vector,
winrt::IInspectable const& e)
{
OnVectorChanged(nullptr, e.as<winrt::IVectorChangedEventArgs>());
}
}

View File

@@ -1,65 +0,0 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
#pragma once
namespace GraphControl
{
public enum class DataSourceChangedAction
{
Insert,
Remove,
Replace,
Reset
};
value struct DataSourceChangedEventArgs sealed
{
DataSourceChangedAction Action;
int OldStartingIndex;
int OldItemsCount;
int NewStartingIndex;
int NewItemsCount;
};
ref class InspectingDataSource sealed
{
internal:
InspectingDataSource(Platform::Object^ source);
event Windows::Foundation::TypedEventHandler<InspectingDataSource^, DataSourceChangedEventArgs>^ DataSourceChanged;
unsigned int GetSize();
Platform::Object^ GetAt(unsigned int index);
std::optional<unsigned int> IndexOf(Platform::Object^ value);
private:
~InspectingDataSource();
static winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable>
WrapIterable(const winrt::Windows::Foundation::Collections::IIterable<winrt::Windows::Foundation::IInspectable>& iterable);
void ListenToCollectionChanges();
void UnlistenToCollectionChanges();
void OnCollectionChanged(
const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Windows::UI::Xaml::Interop::NotifyCollectionChangedEventArgs& e);
void OnVectorChanged(
const winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::Foundation::IInspectable>& sender,
const winrt::Windows::Foundation::Collections::IVectorChangedEventArgs& e);
void OnBindableVectorChanged(
winrt::Windows::UI::Xaml::Interop::IBindableObservableVector const& vector,
winrt::Windows::Foundation::IInspectable const& e);
private:
winrt::Windows::Foundation::Collections::IVector<winrt::Windows::Foundation::IInspectable> m_vector;
winrt::Windows::UI::Xaml::Interop::INotifyCollectionChanged m_notifyCollectionChanged;
winrt::Windows::Foundation::Collections::IObservableVector<winrt::Windows::Foundation::IInspectable> m_observableVector;
winrt::Windows::UI::Xaml::Interop::IBindableObservableVector m_bindableObservableVector;
winrt::event_token m_eventToken;
};
}

View File

@@ -307,7 +307,6 @@
<ClInclude Include="Control\Equation.h" />
<ClInclude Include="Control\EquationCollection.h" />
<ClInclude Include="Control\Grapher.h" />
<ClInclude Include="Control\InspectingDataSource.h" />
<ClInclude Include="DirectX\ActiveTracingPointRenderer.h" />
<ClInclude Include="DirectX\DeviceResources.h" />
<ClInclude Include="DirectX\DirectXHelper.h" />
@@ -319,7 +318,6 @@
<ItemGroup>
<ClCompile Include="Control\Equation.cpp" />
<ClCompile Include="Control\Grapher.cpp" />
<ClCompile Include="Control\InspectingDataSource.cpp" />
<ClCompile Include="DirectX\ActiveTracingPointRenderer.cpp" />
<ClCompile Include="DirectX\DeviceResources.cpp" />
<ClCompile Include="DirectX\NearestPointRenderer.cpp" />

View File

@@ -25,9 +25,6 @@
<ClCompile Include="Control\Grapher.cpp">
<Filter>Control</Filter>
</ClCompile>
<ClCompile Include="Control\InspectingDataSource.cpp">
<Filter>Control</Filter>
</ClCompile>
<ClCompile Include="DirectX\NearestPointRenderer.cpp">
<Filter>DirectX</Filter>
</ClCompile>
@@ -56,9 +53,6 @@
<ClInclude Include="Control\Grapher.h">
<Filter>Control</Filter>
</ClInclude>
<ClInclude Include="Control\InspectingDataSource.h">
<Filter>Control</Filter>
</ClInclude>
<ClInclude Include="DirectX\NearestPointRenderer.h">
<Filter>DirectX</Filter>
</ClInclude>