diff --git a/src/CalcViewModel/CalcViewModel.vcxproj b/src/CalcViewModel/CalcViewModel.vcxproj
index be43a550..711c9383 100644
--- a/src/CalcViewModel/CalcViewModel.vcxproj
+++ b/src/CalcViewModel/CalcViewModel.vcxproj
@@ -331,6 +331,7 @@
+
diff --git a/src/CalcViewModel/CalcViewModel.vcxproj.filters b/src/CalcViewModel/CalcViewModel.vcxproj.filters
index 9e97ecb8..98235248 100644
--- a/src/CalcViewModel/CalcViewModel.vcxproj.filters
+++ b/src/CalcViewModel/CalcViewModel.vcxproj.filters
@@ -217,6 +217,9 @@
Common
+
+ GraphingCalculator
+
diff --git a/src/CalcViewModel/Common/Utils.h b/src/CalcViewModel/Common/Utils.h
index 4bdfbcf9..9e532870 100644
--- a/src/CalcViewModel/Common/Utils.h
+++ b/src/CalcViewModel/Common/Utils.h
@@ -10,6 +10,8 @@
// Utility macros to make Models easier to write
// generates a member variable called m_
+#define SINGLE_ARG(...) __VA_ARGS__
+
#define PROPERTY_R(t, n) \
property t n \
{ \
@@ -72,25 +74,6 @@ private:
\
public:
-#define OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(t, n) \
- property t n \
- { \
- t get() \
- { \
- return m_##n; \
- } \
- void set(t value) \
- { \
- m_##n = value; \
- RaisePropertyChanged(L#n); \
- } \
- } \
- \
-private: \
- t m_##n; \
- \
-public:
-
#define OBSERVABLE_PROPERTY_RW(t, n) \
property t n \
{ \
diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp
index b2eca554..94b97794 100644
--- a/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp
+++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.cpp
@@ -32,9 +32,9 @@ namespace CalculatorApp::ViewModel
{
}
- EquationViewModel::EquationViewModel(GraphControl::Equation ^ equation)
+ EquationViewModel::EquationViewModel(Equation ^ equation, int functionLabelIndex, Windows::UI::Color color)
: m_AnalysisErrorVisible{ false }
- , m_FunctionLabelIndex{ 0 }
+ , m_FunctionLabelIndex{ functionLabelIndex }
, m_KeyGraphFeaturesItems{ ref new Vector() }
, m_resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() }
{
@@ -44,18 +44,20 @@ namespace CalculatorApp::ViewModel
}
GraphEquation = equation;
+ LineColor = color;
+ IsLineEnabled = true;
}
- void EquationViewModel::PopulateKeyGraphFeatures()
+ void EquationViewModel::PopulateKeyGraphFeatures(KeyGraphFeaturesInfo ^ graphEquation)
{
- if (GraphEquation->AnalysisError != 0)
+ if (graphEquation->AnalysisError != 0)
{
AnalysisErrorVisible = true;
- if (GraphEquation->AnalysisError == static_cast(AnalysisErrorType::AnalysisCouldNotBePerformed))
+ if (graphEquation->AnalysisError == static_cast(AnalysisErrorType::AnalysisCouldNotBePerformed))
{
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisCouldNotBePerformed");
}
- else if (GraphEquation->AnalysisError == static_cast(AnalysisErrorType::AnalysisNotSupported))
+ else if (graphEquation->AnalysisError == static_cast(AnalysisErrorType::AnalysisNotSupported))
{
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisNotSupported");
}
@@ -64,26 +66,23 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Clear();
- AddKeyGraphFeature(m_resourceLoader->GetString(L"Domain"), GraphEquation->Domain, m_resourceLoader->GetString(L"KGFDomainNone"));
- AddKeyGraphFeature(m_resourceLoader->GetString(L"Range"), GraphEquation->Range, m_resourceLoader->GetString(L"KGFRangeNone"));
- AddKeyGraphFeature(m_resourceLoader->GetString(L"XIntercept"), GraphEquation->XIntercept, m_resourceLoader->GetString(L"KGFXInterceptNone"));
- AddKeyGraphFeature(m_resourceLoader->GetString(L"YIntercept"), GraphEquation->YIntercept, m_resourceLoader->GetString(L"KGFYInterceptNone"));
- AddKeyGraphFeature(m_resourceLoader->GetString(L"Minima"), GraphEquation->Minima, m_resourceLoader->GetString(L"KGFMinimaNone"));
- AddKeyGraphFeature(m_resourceLoader->GetString(L"Maxima"), GraphEquation->Maxima, m_resourceLoader->GetString(L"KGFMaximaNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"Domain"), graphEquation->Domain, m_resourceLoader->GetString(L"KGFDomainNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"Range"), graphEquation->Range, m_resourceLoader->GetString(L"KGFRangeNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"XIntercept"), graphEquation->XIntercept, m_resourceLoader->GetString(L"KGFXInterceptNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"YIntercept"), graphEquation->YIntercept, m_resourceLoader->GetString(L"KGFYInterceptNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"Minima"), graphEquation->Minima, m_resourceLoader->GetString(L"KGFMinimaNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"Maxima"), graphEquation->Maxima, m_resourceLoader->GetString(L"KGFMaximaNone"));
+ AddKeyGraphFeature(m_resourceLoader->GetString(L"InflectionPoints"), graphEquation->InflectionPoints, m_resourceLoader->GetString(L"KGFInflectionPointsNone"));
AddKeyGraphFeature(
- m_resourceLoader->GetString(L"InflectionPoints"), GraphEquation->InflectionPoints, m_resourceLoader->GetString(L"KGFInflectionPointsNone"));
+ m_resourceLoader->GetString(L"VerticalAsymptotes"), graphEquation->VerticalAsymptotes, m_resourceLoader->GetString(L"KGFVerticalAsymptotesNone"));
AddKeyGraphFeature(
- m_resourceLoader->GetString(L"VerticalAsymptotes"), GraphEquation->VerticalAsymptotes, m_resourceLoader->GetString(L"KGFVerticalAsymptotesNone"));
+ m_resourceLoader->GetString(L"HorizontalAsymptotes"), graphEquation->HorizontalAsymptotes, m_resourceLoader->GetString(L"KGFHorizontalAsymptotesNone"));
AddKeyGraphFeature(
- m_resourceLoader->GetString(L"HorizontalAsymptotes"),
- GraphEquation->HorizontalAsymptotes,
- m_resourceLoader->GetString(L"KGFHorizontalAsymptotesNone"));
- AddKeyGraphFeature(
- m_resourceLoader->GetString(L"ObliqueAsymptotes"), GraphEquation->ObliqueAsymptotes, m_resourceLoader->GetString(L"KGFObliqueAsymptotesNone"));
- AddParityKeyGraphFeature();
- AddPeriodicityKeyGraphFeature();
- AddMonotoncityKeyGraphFeature();
- AddTooComplexKeyGraphFeature();
+ m_resourceLoader->GetString(L"ObliqueAsymptotes"), graphEquation->ObliqueAsymptotes, m_resourceLoader->GetString(L"KGFObliqueAsymptotesNone"));
+ AddParityKeyGraphFeature(graphEquation);
+ AddPeriodicityKeyGraphFeature(graphEquation);
+ AddMonotoncityKeyGraphFeature(graphEquation);
+ AddTooComplexKeyGraphFeature(graphEquation);
AnalysisErrorVisible = false;
}
@@ -125,11 +124,11 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(item);
}
- void EquationViewModel::AddParityKeyGraphFeature()
+ void EquationViewModel::AddParityKeyGraphFeature(KeyGraphFeaturesInfo ^ graphEquation)
{
KeyGraphFeaturesItem ^ parityItem = ref new KeyGraphFeaturesItem();
parityItem->Title = m_resourceLoader->GetString(L"Parity");
- switch (GraphEquation->Parity)
+ switch (graphEquation->Parity)
{
case 0:
parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityUnknown"));
@@ -151,11 +150,11 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(parityItem);
}
- void EquationViewModel::AddPeriodicityKeyGraphFeature()
+ void EquationViewModel::AddPeriodicityKeyGraphFeature(KeyGraphFeaturesInfo ^ graphEquation)
{
KeyGraphFeaturesItem ^ periodicityItem = ref new KeyGraphFeaturesItem();
periodicityItem->Title = m_resourceLoader->GetString(L"Periodicity");
- switch (GraphEquation->PeriodicityDirection)
+ switch (graphEquation->PeriodicityDirection)
{
case 0:
// Periodicity is not supported or is too complex to calculate.
@@ -163,14 +162,14 @@ namespace CalculatorApp::ViewModel
// SetTooComplexFeaturesErrorProperty will set the too complex error when periodicity is supported and unknown
return;
case 1:
- if (GraphEquation->PeriodicityExpression == L"")
+ if (graphEquation->PeriodicityExpression == L"")
{
periodicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFPeriodicityUnknown"));
periodicityItem->IsText = true;
}
else
{
- periodicityItem->DisplayItems->Append(GraphEquation->PeriodicityExpression);
+ periodicityItem->DisplayItems->Append(graphEquation->PeriodicityExpression);
periodicityItem->IsText = false;
}
break;
@@ -186,13 +185,13 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(periodicityItem);
}
- void EquationViewModel::AddMonotoncityKeyGraphFeature()
+ void EquationViewModel::AddMonotoncityKeyGraphFeature(KeyGraphFeaturesInfo ^ graphEquation)
{
KeyGraphFeaturesItem ^ monotonicityItem = ref new KeyGraphFeaturesItem();
monotonicityItem->Title = m_resourceLoader->GetString(L"Monotonicity");
- if (GraphEquation->Monotonicity->Size != 0)
+ if (graphEquation->Monotonicity->Size != 0)
{
- for (auto item : GraphEquation->Monotonicity)
+ for (auto item : graphEquation->Monotonicity)
{
GridDisplayItems ^ gridItem = ref new GridDisplayItems();
gridItem->Expression = item->Key;
@@ -230,9 +229,9 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(monotonicityItem);
}
- void EquationViewModel::AddTooComplexKeyGraphFeature()
+ void EquationViewModel::AddTooComplexKeyGraphFeature(KeyGraphFeaturesInfo ^ graphEquation)
{
- if (GraphEquation->TooComplexFeatures <= 0)
+ if (graphEquation->TooComplexFeatures <= 0)
{
return;
}
@@ -240,55 +239,55 @@ namespace CalculatorApp::ViewModel
Platform::String ^ separator = ref new String(LocalizationSettings::GetInstance().GetListSeparator().c_str());
wstring error;
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Domain) == KeyGraphFeaturesFlag::Domain)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Domain) == KeyGraphFeaturesFlag::Domain)
{
error.append((m_resourceLoader->GetString(L"Domain") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Range) == KeyGraphFeaturesFlag::Range)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Range) == KeyGraphFeaturesFlag::Range)
{
error.append((m_resourceLoader->GetString(L"Range") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Zeros) == KeyGraphFeaturesFlag::Zeros)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Zeros) == KeyGraphFeaturesFlag::Zeros)
{
error.append((m_resourceLoader->GetString(L"XIntercept") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::YIntercept) == KeyGraphFeaturesFlag::YIntercept)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::YIntercept) == KeyGraphFeaturesFlag::YIntercept)
{
error.append((m_resourceLoader->GetString(L"YIntercept") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Parity) == KeyGraphFeaturesFlag::Parity)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Parity) == KeyGraphFeaturesFlag::Parity)
{
error.append((m_resourceLoader->GetString(L"Parity") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Periodicity) == KeyGraphFeaturesFlag::Periodicity)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Periodicity) == KeyGraphFeaturesFlag::Periodicity)
{
error.append((m_resourceLoader->GetString(L"Periodicity") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Minima) == KeyGraphFeaturesFlag::Minima)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Minima) == KeyGraphFeaturesFlag::Minima)
{
error.append((m_resourceLoader->GetString(L"Minima") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Maxima) == KeyGraphFeaturesFlag::Maxima)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Maxima) == KeyGraphFeaturesFlag::Maxima)
{
error.append((m_resourceLoader->GetString(L"Maxima") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::InflectionPoints) == KeyGraphFeaturesFlag::InflectionPoints)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::InflectionPoints) == KeyGraphFeaturesFlag::InflectionPoints)
{
error.append((m_resourceLoader->GetString(L"InflectionPoints") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::VerticalAsymptotes) == KeyGraphFeaturesFlag::VerticalAsymptotes)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::VerticalAsymptotes) == KeyGraphFeaturesFlag::VerticalAsymptotes)
{
error.append((m_resourceLoader->GetString(L"VerticalAsymptotes") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::HorizontalAsymptotes) == KeyGraphFeaturesFlag::HorizontalAsymptotes)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::HorizontalAsymptotes) == KeyGraphFeaturesFlag::HorizontalAsymptotes)
{
error.append((m_resourceLoader->GetString(L"HorizontalAsymptotes") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::ObliqueAsymptotes) == KeyGraphFeaturesFlag::ObliqueAsymptotes)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::ObliqueAsymptotes) == KeyGraphFeaturesFlag::ObliqueAsymptotes)
{
error.append((m_resourceLoader->GetString(L"ObliqueAsymptotes") + separator + L" ")->Data());
}
- if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::MonotoneIntervals) == KeyGraphFeaturesFlag::MonotoneIntervals)
+ if ((graphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::MonotoneIntervals) == KeyGraphFeaturesFlag::MonotoneIntervals)
{
error.append((m_resourceLoader->GetString(L"Monotonicity") + separator + L" ")->Data());
}
@@ -300,5 +299,4 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(tooComplexItem);
}
-
}
diff --git a/src/CalcViewModel/GraphingCalculator/EquationViewModel.h b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h
index 299569b6..5ed0870d 100644
--- a/src/CalcViewModel/GraphingCalculator/EquationViewModel.h
+++ b/src/CalcViewModel/GraphingCalculator/EquationViewModel.h
@@ -5,6 +5,12 @@
#include "../Common/Utils.h"
+namespace GraphControl
+{
+ ref class Equation;
+ ref class KeyGraphFeaturesInfo;
+}
+
namespace CalculatorApp::ViewModel
{
public
@@ -31,16 +37,15 @@ public
OBSERVABLE_PROPERTY_RW(bool, IsText);
};
-
public
ref class EquationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
- EquationViewModel(GraphControl::Equation ^ equation);
+ EquationViewModel(GraphControl::Equation ^ equation, int functionLabelIndex, Windows::UI::Color color);
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(GraphControl::Equation ^, GraphEquation);
- OBSERVABLE_PROPERTY_RW(int, FunctionLabelIndex);
+ OBSERVABLE_PROPERTY_R(int, FunctionLabelIndex);
OBSERVABLE_PROPERTY_RW(bool, IsLastItemInList);
property Platform::String ^ Expression
@@ -59,15 +64,15 @@ public
}
}
- property Windows::UI::Xaml::Media::SolidColorBrush ^ LineColor
+ property Windows::UI::Color LineColor
{
- Windows::UI::Xaml::Media::SolidColorBrush ^ get()
+ Windows::UI::Color get()
{
return GraphEquation->LineColor;
}
- void set(Windows::UI::Xaml::Media::SolidColorBrush ^ value)
+ void set(Windows::UI::Color value)
{
- if (GraphEquation->LineColor != value)
+ if (!Utils::AreColorsEqual(GraphEquation->LineColor, value))
{
GraphEquation->LineColor = value;
RaisePropertyChanged("LineColor");
@@ -96,7 +101,7 @@ public
OBSERVABLE_PROPERTY_R(bool, AnalysisErrorVisible);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, KeyGraphFeaturesItems)
- void PopulateKeyGraphFeatures();
+ void PopulateKeyGraphFeatures(GraphControl::KeyGraphFeaturesInfo ^ info);
private:
void AddKeyGraphFeature(Platform::String ^ title, Platform::String ^ expression, Platform::String ^ errorString);
@@ -104,13 +109,12 @@ public
Platform::String ^ title,
Windows::Foundation::Collections::IVector ^ expressionVector,
Platform::String ^ errorString);
- void AddParityKeyGraphFeature();
- void AddPeriodicityKeyGraphFeature();
- void AddMonotoncityKeyGraphFeature();
- void AddTooComplexKeyGraphFeature();
+ void AddParityKeyGraphFeature(GraphControl::KeyGraphFeaturesInfo ^ info);
+ void AddPeriodicityKeyGraphFeature(GraphControl::KeyGraphFeaturesInfo ^ info);
+ void AddMonotoncityKeyGraphFeature(GraphControl::KeyGraphFeaturesInfo ^ info);
+ void AddTooComplexKeyGraphFeature(GraphControl::KeyGraphFeaturesInfo ^ info);
Windows::Foundation::Collections::IObservableMap ^ m_Monotonicity;
Windows::ApplicationModel::Resources::ResourceLoader ^ m_resourceLoader;
};
-
}
diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp
index 07b6fc13..974cf8f8 100644
--- a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp
+++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.cpp
@@ -15,27 +15,30 @@ namespace CalculatorApp::ViewModel
{
GraphingCalculatorViewModel::GraphingCalculatorViewModel()
: m_IsDecimalEnabled{ true }
- , m_Equations{ ref new Vector< EquationViewModel^ >() }
- , m_Variables{ ref new Vector< VariableViewModel^ >() }
+ , m_Equations{ ref new Vector() }
+ , m_Variables{ ref new Vector() }
{
}
- void GraphingCalculatorViewModel::OnButtonPressed(Object^ parameter)
+ void GraphingCalculatorViewModel::OnButtonPressed(Object ^ parameter)
{
}
- void GraphingCalculatorViewModel::UpdateVariables(IMap^ variables)
+ void GraphingCalculatorViewModel::UpdateVariables(IMap ^ variables)
{
Variables->Clear();
for (auto var : variables)
{
auto variable = ref new VariableViewModel(var->Key, var->Value);
- variable->VariableUpdated += ref new EventHandler([this, variable](Object^ sender, VariableChangedEventArgs e)
- {
- VariableUpdated(variable, VariableChangedEventArgs{ e.variableName, e.newValue });
- });
+ variable->VariableUpdated += ref new EventHandler([this, variable](Object ^ sender, VariableChangedEventArgs e) {
+ VariableUpdated(variable, VariableChangedEventArgs{ e.variableName, e.newValue });
+ });
Variables->Append(variable);
-
}
}
+
+ void GraphingCalculatorViewModel::SetSelectedEquation(EquationViewModel ^ equation)
+ {
+ SelectedEquation = equation;
+ }
}
diff --git a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h
index 18a60543..78e89479 100644
--- a/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h
+++ b/src/CalcViewModel/GraphingCalculator/GraphingCalculatorViewModel.h
@@ -5,66 +5,10 @@
#include "../Common/Utils.h"
#include "EquationViewModel.h"
+#include "VariableViewModel.h"
namespace CalculatorApp::ViewModel
{
-public
- value struct VariableChangedEventArgs sealed
- {
- Platform::String ^ variableName;
- double newValue;
- };
-
- [Windows::UI::Xaml::Data::Bindable] public ref class VariableViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
- {
- public:
- VariableViewModel(Platform::String ^ name, double value)
- : m_Name(name)
- , m_Value(value)
- , m_SliderSettingsVisible(false)
- , m_Min(0.0)
- , m_Step(0.1)
- , m_Max(2.0)
- {
- }
-
- OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
-
- OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
-
- // TODO: Consider removing this work around and manually set the textbox text.
- OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Value);
- OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Min);
- OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Step);
- OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(double, Max);
- OBSERVABLE_PROPERTY_RW(bool, SliderSettingsVisible);
-
- event Windows::Foundation::EventHandler ^ VariableUpdated;
-
- void SetValue(double value)
- {
- if (value < Min)
- {
- value = Min;
- }
- else if (value > Max)
- {
- value = Max;
- }
-
- Value = value;
- }
-
- private:
- void OnPropertyChanged(Platform::String ^ propertyName)
- {
- if (propertyName == "Value")
- {
- VariableUpdated(this, VariableChangedEventArgs{ Name, Value });
- }
- }
- };
-
[Windows::UI::Xaml::Data::Bindable] public ref class GraphingCalculatorViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
@@ -74,6 +18,7 @@ public
OBSERVABLE_PROPERTY_R(bool, IsDecimalEnabled);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Equations);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector ^, Variables);
+ OBSERVABLE_PROPERTY_R(EquationViewModel ^, SelectedEquation);
COMMAND_FOR_METHOD(ButtonPressed, GraphingCalculatorViewModel::OnButtonPressed);
@@ -81,6 +26,7 @@ public
void UpdateVariables(Windows::Foundation::Collections::IMap ^ variables);
+ void SetSelectedEquation(EquationViewModel ^ equation);
private:
void OnButtonPressed(Platform::Object ^ parameter);
};
diff --git a/src/CalcViewModel/GraphingCalculator/VariableViewModel.h b/src/CalcViewModel/GraphingCalculator/VariableViewModel.h
new file mode 100644
index 00000000..d4dd699e
--- /dev/null
+++ b/src/CalcViewModel/GraphingCalculator/VariableViewModel.h
@@ -0,0 +1,69 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+
+#include "../Common/Utils.h"
+#include "EquationViewModel.h"
+
+namespace CalculatorApp::ViewModel
+{
+public
+ value struct VariableChangedEventArgs sealed
+ {
+ Platform::String ^ variableName;
+ double newValue;
+ };
+
+ [Windows::UI::Xaml::Data::Bindable] public ref class VariableViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
+ {
+ public:
+ VariableViewModel(Platform::String ^ name, double value)
+ : m_Name(name)
+ , m_Value(value)
+ , m_SliderSettingsVisible(false)
+ , m_Min(0.0)
+ , m_Step(0.1)
+ , m_Max(2.0)
+ {
+ }
+
+ OBSERVABLE_OBJECT();
+ OBSERVABLE_PROPERTY_R(Platform::String ^, Name);
+ OBSERVABLE_PROPERTY_RW(double, Min);
+ OBSERVABLE_PROPERTY_RW(double, Step);
+ OBSERVABLE_PROPERTY_RW(double, Max);
+ OBSERVABLE_PROPERTY_RW(bool, SliderSettingsVisible);
+
+ event Windows::Foundation::EventHandler ^ VariableUpdated;
+
+ property double Value
+ {
+ double get()
+ {
+ return m_Value;
+ }
+ void set(double value)
+ {
+ if (value < Min)
+ {
+ value = Min;
+ }
+ else if (value > Max)
+ {
+ value = Max;
+ }
+
+ if (Value != value)
+ {
+ m_Value = value;
+ VariableUpdated(this, VariableChangedEventArgs{ Name, value });
+ RaisePropertyChanged(L"Value");
+ }
+ }
+ }
+
+ private:
+ double m_Value;
+ };
+}
diff --git a/src/Calculator/Controls/EquationTextBox.cpp b/src/Calculator/Controls/EquationTextBox.cpp
index 57f5a13e..ef3d7514 100644
--- a/src/Calculator/Controls/EquationTextBox.cpp
+++ b/src/Calculator/Controls/EquationTextBox.cpp
@@ -11,7 +11,6 @@ using namespace Platform;
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
using namespace CalculatorApp::Controls;
-using namespace CalculatorApp::ViewModel;
using namespace Windows::System;
using namespace Windows::Foundation;
using namespace Windows::ApplicationModel;
diff --git a/src/Calculator/EquationStylePanelControl.xaml.cpp b/src/Calculator/EquationStylePanelControl.xaml.cpp
index b964ebaf..e143d07a 100644
--- a/src/Calculator/EquationStylePanelControl.xaml.cpp
+++ b/src/Calculator/EquationStylePanelControl.xaml.cpp
@@ -32,11 +32,19 @@ void EquationStylePanelControl::SelectionChanged(Object ^ /*sender */, Selection
{
if (e->AddedItems->Size > 0)
{
- SelectedColor = static_cast(e->AddedItems->GetAt(0));
+ auto brush = dynamic_cast(e->AddedItems->GetAt(0));
+ if (brush == nullptr)
+ {
+ SelectedColor = Colors::Black;
+ }
+ else
+ {
+ SelectedColor = brush->Color;
+ }
}
}
-void EquationStylePanelControl::OnSelectedColorPropertyChanged(SolidColorBrush ^ /*oldColor*/, SolidColorBrush ^ newColor)
+void EquationStylePanelControl::OnSelectedColorPropertyChanged(Color /*oldColor*/, Color newColor)
{
SelectColor(newColor);
}
@@ -46,13 +54,8 @@ void EquationStylePanelControl::ColorChooserLoaded(Object ^ sender, RoutedEventA
SelectColor(SelectedColor);
}
-void EquationStylePanelControl::SelectColor(SolidColorBrush ^ selectedColor)
+void EquationStylePanelControl::SelectColor(Color selectedColor)
{
- if (selectedColor == nullptr)
- {
- return;
- }
-
for (auto item : ColorChooser->Items->GetView())
{
auto brush = static_cast(item);
@@ -63,7 +66,7 @@ void EquationStylePanelControl::SelectColor(SolidColorBrush ^ selectedColor)
continue;
}
- if (brush->Color == selectedColor->Color)
+ if (Utils::AreColorsEqual(brush->Color, selectedColor))
{
gridViewItem->IsSelected = true;
return;
diff --git a/src/Calculator/EquationStylePanelControl.xaml.h b/src/Calculator/EquationStylePanelControl.xaml.h
index 25539b83..b3c3aabb 100644
--- a/src/Calculator/EquationStylePanelControl.xaml.h
+++ b/src/Calculator/EquationStylePanelControl.xaml.h
@@ -14,13 +14,15 @@ namespace CalculatorApp
EquationStylePanelControl();
DEPENDENCY_PROPERTY_OWNER(EquationStylePanelControl);
- DEPENDENCY_PROPERTY_WITH_CALLBACK(Windows::UI::Xaml::Media::SolidColorBrush ^, SelectedColor);
+ DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(Windows::UI::Color, SelectedColor, Windows::UI::Colors::Black);
DEPENDENCY_PROPERTY_WITH_DEFAULT(Windows::Foundation::Collections::IVector ^, AvailableColors, nullptr);
private:
void SelectionChanged(Platform::Object ^ sender, Windows::UI::Xaml::Controls::SelectionChangedEventArgs ^ e);
- void OnSelectedColorPropertyChanged(Windows::UI::Xaml::Media::SolidColorBrush ^ oldValue, Windows::UI::Xaml::Media::SolidColorBrush ^ newValue);
- void ColorChooserLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
- void SelectColor(Windows::UI::Xaml::Media::SolidColorBrush ^ selectedColor);
+ void OnSelectedColorPropertyChanged(Windows::UI::Color oldColor, Windows::UI::Color newColor);
+ void ColorChooserLoaded(
+ Platform::Object ^ sender,
+ Windows::UI::Xaml::RoutedEventArgs ^ e);
+ void SelectColor(Windows::UI::Color selectedColor);
};
}
diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml
index 7c729a93..3f82bfaa 100644
--- a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml
+++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml
@@ -235,7 +235,7 @@
DataContextChanged="InputTextBox_DataContextChanged"
EquationButtonClicked="EquationTextBox_EquationButtonClicked"
EquationButtonContentIndex="{x:Bind FunctionLabelIndex, Mode=OneWay}"
- EquationColor="{x:Bind LineColor, Mode=OneWay}"
+ EquationColor="{x:Bind local:EquationInputArea.ToSolidColorBrush(LineColor), Mode=OneWay}"
EquationSubmitted="InputTextBox_Submitted"
GotFocus="InputTextBox_GotFocus"
HasError="{x:Bind GraphEquation.HasGraphError, Mode=OneWay}"
diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.cpp b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.cpp
index d39b4668..da084aa7 100644
--- a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.cpp
+++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.cpp
@@ -7,6 +7,7 @@
using namespace CalculatorApp;
using namespace CalculatorApp::Common;
+using namespace GraphControl;
using namespace CalculatorApp::ViewModel;
using namespace CalculatorApp::Controls;
using namespace Platform;
@@ -61,19 +62,14 @@ void EquationInputArea::OnEquationsPropertyChanged()
void EquationInputArea::AddNewEquation()
{
- auto eq = ref new EquationViewModel(ref new Equation());
- eq->IsLastItemInList = true;
-
if (Equations->Size > 0)
{
Equations->GetAt(Equations->Size - 1)->IsLastItemInList = false;
}
m_lastLineColorIndex = (m_lastLineColorIndex + 1) % AvailableColors->Size;
-
- eq->LineColor = AvailableColors->GetAt(m_lastLineColorIndex);
- eq->IsLineEnabled = true;
- eq->FunctionLabelIndex = ++m_lastFunctionLabelIndex;
+ auto eq = ref new EquationViewModel(ref new Equation(), ++m_lastFunctionLabelIndex, AvailableColors->GetAt(m_lastLineColorIndex)->Color);
+ eq->IsLastItemInList = true;
m_equationToFocus = eq;
Equations->Append(eq);
}
@@ -192,8 +188,7 @@ void EquationInputArea::EquationTextBox_KeyGraphFeaturesButtonClicked(Object ^ s
}
auto eq = static_cast(tb->DataContext);
- EquationVM = eq;
- KeyGraphFeaturesRequested(EquationVM, ref new RoutedEventArgs());
+ KeyGraphFeaturesRequested(this, eq);
}
void EquationInputArea::EquationTextBox_EquationButtonClicked(Object ^ sender, RoutedEventArgs ^ e)
@@ -210,7 +205,7 @@ void EquationInputArea::InputTextBox_Loaded(Object ^ sender, RoutedEventArgs ^ e
auto colorChooser = static_cast(tb->ColorChooserFlyout->Content);
colorChooser->AvailableColors = AvailableColors;
- if (m_equationToFocus!=nullptr && tb->DataContext == m_equationToFocus)
+ if (m_equationToFocus != nullptr && tb->DataContext == m_equationToFocus)
{
m_equationToFocus = nullptr;
tb->FocusTextBox();
@@ -227,9 +222,7 @@ void EquationInputArea::InputTextBox_Loaded(Object ^ sender, RoutedEventArgs ^ e
}
}
-void EquationInputArea::InputTextBox_DataContextChanged(
- Windows::UI::Xaml::FrameworkElement ^ sender,
- Windows::UI::Xaml::DataContextChangedEventArgs ^ args)
+void EquationInputArea::InputTextBox_DataContextChanged(Windows::UI::Xaml::FrameworkElement ^ sender, Windows::UI::Xaml::DataContextChangedEventArgs ^ args)
{
auto tb = static_cast(sender);
if (!tb->IsLoaded)
@@ -237,7 +230,7 @@ void EquationInputArea::InputTextBox_DataContextChanged(
return;
}
- FocusEquationIfNecessary(tb);
+ FocusEquationIfNecessary(tb);
}
void EquationInputArea::FocusEquationIfNecessary(CalculatorApp::Controls::EquationTextBox ^ textBox)
@@ -296,18 +289,12 @@ void EquationInputArea::ReloadAvailableColors(bool isHighContrast)
return;
}
- // Use a blank brush to clear out the color before setting it. This is needed because going
- // from High Contrast White -> High Contrast Black, the high contrast colors seem to be equivalent,
- // causing the change to not take place.
- auto blankBrush = ref new SolidColorBrush();
-
// Reassign colors for each equation
m_lastLineColorIndex = -1;
for (auto equationViewModel : Equations)
{
m_lastLineColorIndex = (m_lastLineColorIndex + 1) % AvailableColors->Size;
- equationViewModel->LineColor = blankBrush;
- equationViewModel->LineColor = AvailableColors->GetAt(m_lastLineColorIndex);
+ equationViewModel->LineColor = AvailableColors->GetAt(m_lastLineColorIndex)->Color;
}
}
@@ -319,23 +306,35 @@ void EquationInputArea::TextBoxGotFocus(TextBox ^ sender, RoutedEventArgs ^ e)
void EquationInputArea::SubmitTextbox(TextBox ^ sender)
{
auto variableViewModel = static_cast(sender->DataContext);
-
+ double val;
if (sender->Name == "ValueTextBox")
{
- variableViewModel->SetValue(validateDouble(sender->Text, variableViewModel->Value));
+ val = validateDouble(sender->Text, variableViewModel->Value);
+ variableViewModel->Value = val;
}
else if (sender->Name == "MinTextBox")
{
- variableViewModel->Min = validateDouble(sender->Text, variableViewModel->Min);
+ val = validateDouble(sender->Text, variableViewModel->Min);
+ variableViewModel->Min = val;
}
else if (sender->Name == "MaxTextBox")
{
- variableViewModel->Max = validateDouble(sender->Text, variableViewModel->Max);
+ val = validateDouble(sender->Text, variableViewModel->Max);
+ variableViewModel->Max = val;
}
else if (sender->Name == "StepTextBox")
{
- variableViewModel->Step = validateDouble(sender->Text, variableViewModel->Step);
+ val = validateDouble(sender->Text, variableViewModel->Step);
+ variableViewModel->Step = val;
}
+ else
+ {
+ return;
+ }
+
+ wostringstream oss;
+ oss << std::noshowpoint << val;
+ sender->Text = ref new String(oss.str().c_str());
}
void EquationInputArea::TextBoxLosingFocus(TextBox ^ sender, LosingFocusEventArgs ^)
diff --git a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h
index 50e48638..78612d7c 100644
--- a/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h
+++ b/src/Calculator/Views/GraphingCalculator/EquationInputArea.xaml.h
@@ -23,13 +23,15 @@ namespace CalculatorApp
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, Equations);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, Variables);
- OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(ViewModel::EquationViewModel ^, EquationVM);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector ^, AvailableColors);
- event Windows::UI::Xaml::RoutedEventHandler ^ KeyGraphFeaturesRequested;
+ event Windows::Foundation::EventHandler^ KeyGraphFeaturesRequested;
public:
static Windows::UI::Xaml::Visibility ManageEditVariablesButtonVisibility(unsigned int numberOfVariables);
+ static Windows::UI::Xaml::Media::SolidColorBrush
+ ^ ToSolidColorBrush(Windows::UI::Color color) { return ref new Windows::UI::Xaml::Media::SolidColorBrush(color); }
+
private:
void OnPropertyChanged(Platform::String^ propertyName);
void OnEquationsPropertyChanged();
diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml
index dd2aaae0..5b1c815c 100644
--- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml
+++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml
@@ -480,7 +480,7 @@
Grid.RowSpan="2"
Margin="0,4,0,0"
KeyGraphFeaturesClosed="OnKeyGraphFeaturesClosed"
- ViewModel="{x:Bind EquationInputAreaControl.EquationVM, Mode=OneWay}"
+ ViewModel="{x:Bind ViewModel.SelectedEquation, Mode=OneWay}"
Visibility="{x:Bind IsKeyGraphFeaturesVisible, Mode=OneWay}"
x:Load="{x:Bind IsKeyGraphFeaturesVisible, Mode=OneWay}"/>
diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp
index 182f1c94..690bc90d 100644
--- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp
+++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.cpp
@@ -53,8 +53,6 @@ DEPENDENCY_PROPERTY_INITIALIZATION(GraphingCalculator, IsSmallState);
GraphingCalculator::GraphingCalculator()
{
- Equation::RegisterDependencyProperties();
- Grapher::RegisterDependencyProperties();
InitializeComponent();
DataTransferManager ^ dataTransferManager = DataTransferManager::GetForCurrentView();
@@ -219,7 +217,7 @@ void GraphingCalculator::OnDataRequested(DataTransferManager ^ sender, DataReque
continue;
}
- auto color = equation->LineColor->Color;
+ auto color = equation->LineColor;
hasEquations = true;
expression = GraphingControl->ConvertToLinear(expression);
@@ -380,12 +378,15 @@ void GraphingCalculator::GraphingControl_LosingFocus(UIElement ^ sender, LosingF
}
}
-void GraphingCalculator::OnEquationKeyGraphFeaturesRequested(Object ^ sender, RoutedEventArgs ^ e)
+void GraphingCalculator::OnEquationKeyGraphFeaturesRequested(Object ^ sender, EquationViewModel ^ equationViewModel)
{
- auto equationViewModel = static_cast(sender);
- GraphingControl->AnalyzeEquation(equationViewModel->GraphEquation);
- equationViewModel->PopulateKeyGraphFeatures();
- IsKeyGraphFeaturesVisible = true;
+ ViewModel->SetSelectedEquation(equationViewModel);
+ if (equationViewModel != nullptr)
+ {
+ auto keyGraphFeatureInfo = GraphingControl->AnalyzeEquation(equationViewModel->GraphEquation);
+ equationViewModel->PopulateKeyGraphFeatures(keyGraphFeatureInfo);
+ IsKeyGraphFeaturesVisible = true;
+ }
}
void GraphingCalculator::OnKeyGraphFeaturesClosed(Object ^ sender, RoutedEventArgs ^ e)
diff --git a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h
index cdf5564e..54b45db1 100644
--- a/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h
+++ b/src/Calculator/Views/GraphingCalculator/GraphingCalculator.xaml.h
@@ -24,7 +24,7 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo
COMMAND_FOR_METHOD(ZoomOutButtonPressed, GraphingCalculator::OnZoomOutCommand);
COMMAND_FOR_METHOD(ZoomInButtonPressed, GraphingCalculator::OnZoomInCommand);
COMMAND_FOR_METHOD(ZoomResetButtonPressed, GraphingCalculator::OnZoomResetCommand);
- OBSERVABLE_PROPERTY_RW(bool, IsKeyGraphFeaturesVisible);
+ OBSERVABLE_PROPERTY_R(bool, IsKeyGraphFeaturesVisible);
DEPENDENCY_PROPERTY(bool, IsSmallState);
property CalculatorApp::ViewModel::GraphingCalculatorViewModel^ ViewModel
@@ -64,7 +64,7 @@ public ref class GraphingCalculator sealed : public Windows::UI::Xaml::Data::INo
void GraphingControl_LostFocus(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void GraphingControl_LosingFocus(Windows::UI::Xaml::UIElement ^ sender, Windows::UI::Xaml::Input::LosingFocusEventArgs ^ args);
void GraphingControl_VariablesUpdated(Platform::Object ^ sender, Object ^ args);
- void OnEquationKeyGraphFeaturesRequested(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
+ void OnEquationKeyGraphFeaturesRequested(Platform::Object ^ sender, CalculatorApp::ViewModel::EquationViewModel ^ e);
void OnKeyGraphFeaturesClosed(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void SwitchModeToggleButton_Checked(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void TraceValuePopup_SizeChanged(Platform::Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
diff --git a/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml
index 0c3ffa75..11d18201 100644
--- a/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml
+++ b/src/Calculator/Views/GraphingCalculator/KeyGraphFeaturesPanel.xaml
@@ -67,7 +67,7 @@
+ Color="{TemplateBinding EquationColor}"/>
@@ -330,8 +330,11 @@
DataContext="{x:Bind ViewModel, Mode=OneWay}"
EquationButtonClicked="EquationButtonClicked"
EquationButtonContentIndex="{x:Bind ViewModel.FunctionLabelIndex, Mode=OneWay}"
- EquationColor="{x:Bind ViewModel.LineColor, Mode=OneWay}"
- Loaded="EquationInputTextBox_Loaded"/>
+ Loaded="EquationInputTextBox_Loaded">
+
+
+
+
::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_maximaProperty)
- {
- s_maximaProperty = DependencyProperty::Register(
- EquationProperties::Maxima,
- IObservableVector::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_domainProperty)
- {
- s_domainProperty = DependencyProperty::Register(
- EquationProperties::Domain,
- String::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_rangeProperty)
- {
- s_rangeProperty = DependencyProperty::Register(
- EquationProperties::Range,
- String::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_inflectionPointsProperty)
- {
- s_inflectionPointsProperty = DependencyProperty::Register(
- EquationProperties::InflectionPoints,
- IObservableVector::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_monotonicityProperty)
- {
- s_monotonicityProperty = DependencyProperty::Register(
- EquationProperties::Monotonicity,
- IObservableMap::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_verticalAsymptotesProperty)
- {
- s_verticalAsymptotesProperty = DependencyProperty::Register(
- EquationProperties::VerticalAsymptotes,
- IObservableVector::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_horizontalAsymptotesProperty)
- {
- s_horizontalAsymptotesProperty = DependencyProperty::Register(
- EquationProperties::HorizontalAsymptotes,
- IObservableVector::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_obliqueAsymptotesProperty)
- {
- s_obliqueAsymptotesProperty = DependencyProperty::Register(
- EquationProperties::ObliqueAsymptotes,
- IObservableVector::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
- if (!s_tooComplexFeaturesProperty)
- {
- s_tooComplexFeaturesProperty = DependencyProperty::Register(
- EquationProperties::TooComplexFeatures,
- int ::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_analysisErrorProperty)
- {
- s_analysisErrorProperty = DependencyProperty::Register(
- EquationProperties::AnalysisError,
- int ::typeid,
- Equation::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Equation::OnCustomDependencyPropertyChanged)));
- }
- }
-
- void Equation::OnCustomDependencyPropertyChanged(DependencyObject ^ obj, DependencyPropertyChangedEventArgs ^ args)
- {
- if (auto eq = static_cast(obj))
- {
- String ^ propertyName = nullptr;
- if (args->Property == s_expressionProperty)
- {
- propertyName = EquationProperties::Expression;
- }
- else if (args->Property == s_lineColorProperty)
- {
- propertyName = EquationProperties::LineColor;
- }
- else if (args->Property == s_isLineEnabledProperty)
- {
- propertyName = EquationProperties::IsLineEnabled;
- }
- else if (args->Property == s_xInterceptProperty)
- {
- propertyName = EquationProperties::XIntercept;
- }
- else if (args->Property == s_yInterceptProperty)
- {
- propertyName = EquationProperties::YIntercept;
- }
- else if (args->Property == s_parityProperty)
- {
- propertyName = EquationProperties::Parity;
- }
- else if (args->Property == s_periodicityDirectionProperty)
- {
- propertyName = EquationProperties::PeriodicityDirection;
- }
- else if (args->Property == s_periodicityExpressionProperty)
- {
- propertyName = EquationProperties::PeriodicityExpression;
- }
- else if (args->Property == s_minimaProperty)
- {
- propertyName = EquationProperties::Minima;
- }
- else if (args->Property == s_maximaProperty)
- {
- propertyName = EquationProperties::Maxima;
- }
- else if (args->Property == s_domainProperty)
- {
- propertyName = EquationProperties::Domain;
- }
- else if (args->Property == s_rangeProperty)
- {
- propertyName = EquationProperties::Range;
- }
- else if (args->Property == s_inflectionPointsProperty)
- {
- propertyName = EquationProperties::InflectionPoints;
- }
- else if (args->Property == s_monotonicityProperty)
- {
- propertyName = EquationProperties::Monotonicity;
- }
- else if (args->Property == s_verticalAsymptotesProperty)
- {
- propertyName = EquationProperties::VerticalAsymptotes;
- }
- else if (args->Property == s_horizontalAsymptotesProperty)
- {
- propertyName = EquationProperties::HorizontalAsymptotes;
- }
- else if (args->Property == s_obliqueAsymptotesProperty)
- {
- propertyName = EquationProperties::ObliqueAsymptotes;
- }
- else if (args->Property == s_tooComplexFeaturesProperty)
- {
- propertyName = EquationProperties::TooComplexFeatures;
- }
- else if (args->Property == s_analysisErrorProperty)
- {
- propertyName = EquationProperties::AnalysisError;
- }
- else if (args->Property == s_hasGraphErrorProperty)
- {
- propertyName = EquationProperties::HasGraphError;
- }
- else if (args->Property == s_isValidatedProperty)
- {
- propertyName = EquationProperties::IsValidated;
- }
-
- eq->PropertyChanged(eq, propertyName);
- }
- }
-
- wstring Equation::GetRequest()
- {
- wstringstream ss{};
- ss << GetRequestHeader() << GetExpression() << GetLineColor() << L"";
-
- return ss.str();
- }
-
- wstring Equation::GetRequestHeader()
- {
- wstring expr{ Expression->Data() };
-
- // Check for unicode characters of less than, less than or equal to, greater than and greater than or equal to.
- if (expr.find(L">><") != wstring::npos || expr.find(L"><<") != wstring::npos || expr.find(L">≥<") != wstring::npos
- || expr.find(L">≤<") != wstring::npos)
- {
- return L"plotIneq2D"s;
- }
- else if (expr.find(L">=<") != wstring::npos)
- {
- return L"plotEq2d"s;
- }
- else
- {
- return L"plot2d"s;
- }
- }
-
- wstring Equation::GetExpression()
- {
- wstring mathML = Expression->Data();
-
- size_t mathPrefix = 0;
- while ((mathPrefix = mathML.find(s_mathPrefix, mathPrefix)) != std::string::npos)
- {
- mathML.replace(mathPrefix, s_mathPrefix.length(), L"");
- mathPrefix += s_mathPrefix.length();
- }
-
- return mathML;
- }
-
- wstring Equation::GetLineColor()
- {
- return L""s;
- }
-
- bool Equation::IsGraphableEquation()
- {
- return !Expression->IsEmpty() && IsLineEnabled && !HasGraphError;
- }
-}
diff --git a/src/GraphControl/Control/Equation.h b/src/GraphControl/Control/Equation.h
deleted file mode 100644
index 2fd32bde..00000000
--- a/src/GraphControl/Control/Equation.h
+++ /dev/null
@@ -1,507 +0,0 @@
-// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License.
-
-#pragma once
-
-namespace GraphControl
-{
- namespace EquationProperties
- {
- extern Platform::String ^ Expression;
- extern Platform::String ^ LineColor;
- extern Platform::String ^ IsLineEnabled;
- }
-
- 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::DependencyObject
- {
- public:
-
- Equation()
- {
- }
-
- static void RegisterDependencyProperties();
-
-#pragma region Platform::String ^ Expression DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ ExpressionProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_expressionProperty;
- }
- }
- property Platform::String^ Expression
- {
- Platform::String^ get()
- {
- return static_cast(GetValue(s_expressionProperty));
- }
- void set(Platform::String^ value)
- {
- SetValue(s_expressionProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::UI::Xaml::Media::SolidColorBrush ^ LineColor DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ LineColorProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_lineColorProperty;
- }
- }
- property Windows::UI::Xaml::Media::SolidColorBrush^ LineColor
- {
- Windows::UI::Xaml::Media::SolidColorBrush^ get()
- {
- return static_cast(GetValue(s_lineColorProperty));
- }
- void set(Windows::UI::Xaml::Media::SolidColorBrush^ value)
- {
- if (value == nullptr || LineColor == nullptr || (value->Color.A != LineColor->Color.A) || (value->Color.R != LineColor->Color.R)
- || (value->Color.G != LineColor->Color.G) || (value->Color.B != LineColor->Color.B))
- SetValue(s_lineColorProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region bool IsLineEnabled DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty ^ IsLineEnabledProperty
- {
- Windows::UI::Xaml::DependencyProperty ^ get()
- {
- return s_isLineEnabledProperty;
- }
- }
- property bool IsLineEnabled
- {
- bool get()
- {
- return static_cast(GetValue(s_isLineEnabledProperty));
- }
- void set(bool value)
- {
- SetValue(s_isLineEnabledProperty, value);
- }
- }
-
-#pragma endregion
-
-#pragma region bool HasGraphError DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty ^ HasGraphErrorProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_hasGraphErrorProperty; } }
-
- property bool HasGraphError
- {
- bool get()
- {
- return static_cast(GetValue(s_hasGraphErrorProperty));
- }
-
- internal:
- void set(bool value)
- {
- SetValue(s_hasGraphErrorProperty, value);
- }
- }
-
-#pragma endregion
-
-#pragma region bool IsValidated DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty ^ IsValidatedProperty { Windows::UI::Xaml::DependencyProperty ^ get() { return s_isValidatedProperty; } }
-
- property bool IsValidated
- {
- bool get()
- {
- return static_cast(GetValue(s_isValidatedProperty));
- }
-
- internal:
- void set(bool value)
- {
- SetValue(s_isValidatedProperty, value);
- }
- }
-
-#pragma endregion
-
-#pragma region Key Graph Features
-
-
-#pragma region Platform::String ^ XIntercept DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ XInterceptProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_xInterceptProperty;
- }
- }
- property Platform::String^ XIntercept
- {
- Platform::String^ get()
- {
- return static_cast(GetValue(s_xInterceptProperty));
- }
- internal: void set(Platform::String^ value)
- {
- SetValue(s_xInterceptProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Platform::String ^ YIntercept DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ YInterceptProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_yInterceptProperty;
- }
- }
- property Platform::String^ YIntercept
- {
- Platform::String^ get()
- {
- return static_cast(GetValue(s_yInterceptProperty));
- }
- internal: void set(Platform::String^ value)
- {
- SetValue(s_yInterceptProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region int Parity DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ ParityProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_parityProperty;
- }
- }
- property int Parity
- {
- int get()
- {
- return static_cast(GetValue(s_parityProperty));
- }
- internal: void set(int value)
- {
- SetValue(s_parityProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region int Periodicity DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ PeriodicityDirectionProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_periodicityDirectionProperty;
- }
- }
- property int PeriodicityDirection
- {
- int get()
- {
- return static_cast(GetValue(s_periodicityDirectionProperty));
- }
- internal: void set(int value)
- {
- SetValue(s_periodicityDirectionProperty, value);
- }
- }
-#pragma endregion
-
- #pragma region Platform::String ^ PeriodicityExpression DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ PeriodicityExpressionProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_periodicityExpressionProperty;
- }
- }
- property Platform::String ^ PeriodicityExpression
- {
- Platform::String ^ get()
- {
- return static_cast(GetValue(s_periodicityExpressionProperty));
- }
- internal: void set(Platform::String ^ value)
- {
- SetValue(s_periodicityExpressionProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ Minima DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ MinimaProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_minimaProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ Minima
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_minimaProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_minimaProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ Maxima DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ MaximaProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_maximaProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ Maxima
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_maximaProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_maximaProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Platform::String ^ Domain DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ DomainProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_domainProperty;
- }
- }
- property Platform::String^ Domain
- {
- Platform::String^ get()
- {
- return static_cast(GetValue(s_domainProperty));
- }
- internal: void set(Platform::String^ value)
- {
- SetValue(s_domainProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Platform::String ^ Range DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ RangeProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_rangeProperty;
- }
- }
- property Platform::String^ Range
- {
- Platform::String^ get()
- {
- return static_cast(GetValue(s_rangeProperty));
- }
- internal: void set(Platform::String^ value)
- {
- SetValue(s_rangeProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ InflectionPoints DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ InflectionPointsProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_inflectionPointsProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ InflectionPoints
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_inflectionPointsProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_inflectionPointsProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IObservableMap < Platform::String ^, Platform::String ^ > ^ Monotonicity DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ MonotonicityProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_monotonicityProperty;
- }
- }
- property Windows::Foundation::Collections::IObservableMap ^ Monotonicity
- {
- Windows::Foundation::Collections::IObservableMap ^ get()
- {
- return static_cast ^>(GetValue(s_monotonicityProperty));
- }
- internal: void set(Windows::Foundation::Collections::IObservableMap ^ value)
- {
- SetValue(s_monotonicityProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ VerticalAsymptotes DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ VerticalAsymptotesProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_verticalAsymptotesProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ VerticalAsymptotes
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_verticalAsymptotesProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_verticalAsymptotesProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ HorizontalAsymptotes DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ HorizontalAsymptotesProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_horizontalAsymptotesProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ HorizontalAsymptotes
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_horizontalAsymptotesProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_horizontalAsymptotesProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IVector < Platform::String ^ > ^ ObliqueAsymptotes DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ ObliqueAsymptotesProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_obliqueAsymptotesProperty;
- }
- }
- property Windows::Foundation::Collections::IVector ^ ObliqueAsymptotes
- {
- Windows::Foundation::Collections::IVector ^ get()
- {
- return static_cast ^>(GetValue(s_obliqueAsymptotesProperty));
- }
- internal: void set(Windows::Foundation::Collections::IVector ^ value)
- {
- SetValue(s_obliqueAsymptotesProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region int TooComplexFeatures DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ TooComplexFeaturesProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_tooComplexFeaturesProperty;
- }
- }
- property int TooComplexFeatures
- {
- int get()
- {
- return static_cast(GetValue(s_tooComplexFeaturesProperty));
- }
- internal: void set(int value)
- {
- SetValue(s_tooComplexFeaturesProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region int AnalysisError DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty ^ AnalysisErrorProperty
- {
- Windows::UI::Xaml::DependencyProperty ^ get()
- {
- return s_analysisErrorProperty;
- }
- }
- property int AnalysisError
- {
- int get()
- {
- return static_cast(GetValue(s_analysisErrorProperty));
- }
- internal: void set(int value)
- {
- SetValue(s_analysisErrorProperty, value);
- }
- }
-
-#pragma endregion
-
- internal : event PropertyChangedEventHandler ^ PropertyChanged;
-
- std::wstring GetRequest();
- bool IsGraphableEquation();
-
- private:
- static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
-
- std::wstring GetRequestHeader();
- std::wstring GetExpression();
- std::wstring GetLineColor();
-
- private:
- static Windows::UI::Xaml::DependencyProperty ^ s_expressionProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_lineColorProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_isLineEnabledProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_hasGraphErrorProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_isValidatedProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_xInterceptProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_yInterceptProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_parityProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_periodicityDirectionProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_periodicityExpressionProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_minimaProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_maximaProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_domainProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_rangeProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_inflectionPointsProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_monotonicityProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_verticalAsymptotesProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_horizontalAsymptotesProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_obliqueAsymptotesProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_tooComplexFeaturesProperty;
- static Windows::UI::Xaml::DependencyProperty ^ s_analysisErrorProperty;
- };
-}
diff --git a/src/GraphControl/Control/Grapher.cpp b/src/GraphControl/Control/Grapher.cpp
index 764bed93..78668859 100644
--- a/src/GraphControl/Control/Grapher.cpp
+++ b/src/GraphControl/Control/Grapher.cpp
@@ -24,16 +24,17 @@ using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
+using namespace GraphControl;
+
+DEPENDENCY_PROPERTY_INITIALIZATION(Grapher, ForceProportionalAxes);
+DEPENDENCY_PROPERTY_INITIALIZATION(Grapher, Variables);
+DEPENDENCY_PROPERTY_INITIALIZATION(Grapher, Equations);
namespace
{
constexpr auto s_defaultStyleKey = L"GraphControl.Grapher";
constexpr auto s_templateKey_SwapChainPanel = L"GraphSurface";
- constexpr auto s_propertyName_Equations = L"Equations";
- constexpr auto s_propertyName_Variables = L"Variables";
- constexpr auto s_propertyName_ForceProportionalAxes = L"ForceProportionalAxes";
-
constexpr auto s_X = L"x";
constexpr auto s_Y = L"y";
constexpr auto s_defaultFormatType = FormatType::MathML;
@@ -52,24 +53,19 @@ namespace
namespace GraphControl
{
- DependencyProperty ^ Grapher::s_equationsProperty;
- DependencyProperty ^ Grapher::s_variablesProperty;
- DependencyProperty ^ Grapher::s_forceProportionalAxesTemplateProperty;
-
Grapher::Grapher()
: m_solver{ IMathSolver::CreateMathSolver() }
, m_graph{ m_solver->CreateGrapher() }
, m_Moving{ false }
{
+ Equations = ref new EquationCollection();
+
m_solver->ParsingOptions().SetFormatType(s_defaultFormatType);
m_solver->FormatOptions().SetFormatType(s_defaultFormatType);
m_solver->FormatOptions().SetMathMLPrefix(wstring(L"mml"));
DefaultStyleKey = StringReference(s_defaultStyleKey);
- this->SetValue(EquationsProperty, ref new EquationCollection());
- this->SetValue(VariablesProperty, ref new Map());
-
this->Loaded += ref new RoutedEventHandler(this, &Grapher::OnLoaded);
this->Unloaded += ref new RoutedEventHandler(this, &Grapher::OnUnloaded);
@@ -147,52 +143,6 @@ namespace GraphControl
TryUpdateGraph();
}
- void Grapher::RegisterDependencyProperties()
- {
- if (!s_equationsProperty)
- {
- s_equationsProperty = DependencyProperty::Register(
- StringReference(s_propertyName_Equations),
- EquationCollection::typeid,
- Grapher::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_variablesProperty)
- {
- s_variablesProperty = DependencyProperty::Register(
- StringReference(s_propertyName_Variables),
- IObservableMap::typeid,
- Grapher::typeid,
- ref new PropertyMetadata(nullptr, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
- }
-
- if (!s_forceProportionalAxesTemplateProperty)
- {
- s_forceProportionalAxesTemplateProperty = DependencyProperty::Register(
- StringReference(s_propertyName_ForceProportionalAxes),
- bool ::typeid,
- Grapher::typeid,
- ref new PropertyMetadata(true, ref new PropertyChangedCallback(&Grapher::OnCustomDependencyPropertyChanged)));
- }
- }
-
- void Grapher::OnCustomDependencyPropertyChanged(DependencyObject ^ obj, DependencyPropertyChangedEventArgs ^ args)
- {
- auto self = static_cast(obj);
- if (self)
- {
- if (args->Property == EquationsProperty)
- {
- self->OnEquationsChanged(args);
- }
- else if (args->Property == ForceProportionalAxesTemplateProperty)
- {
- self->OnForceProportionalAxesChanged(args);
- }
- }
- }
-
void Grapher::OnDependencyPropertyChanged(DependencyObject ^ obj, DependencyProperty ^ p)
{
if (p == SolidColorBrush::ColorProperty)
@@ -202,30 +152,36 @@ namespace GraphControl
}
}
- void Grapher::OnEquationsChanged(DependencyPropertyChangedEventArgs ^ args)
+ void Grapher::OnEquationsPropertyChanged(EquationCollection ^ oldValue, EquationCollection ^ newValue)
{
- if (auto older = static_cast(args->OldValue))
+ if (oldValue != nullptr)
{
if (m_tokenEquationChanged.Value != 0)
{
- older->EquationChanged -= m_tokenEquationChanged;
+ oldValue->EquationChanged -= m_tokenEquationChanged;
m_tokenEquationChanged.Value = 0;
}
if (m_tokenEquationStyleChanged.Value != 0)
{
- older->EquationStyleChanged -= m_tokenEquationStyleChanged;
+ oldValue->EquationStyleChanged -= m_tokenEquationStyleChanged;
m_tokenEquationStyleChanged.Value = 0;
}
+
+ if (m_tokenEquationLineEnabledChanged.Value != 0)
+ {
+ oldValue->EquationLineEnabledChanged -= m_tokenEquationLineEnabledChanged;
+ m_tokenEquationLineEnabledChanged.Value = 0;
+ }
}
- if (auto newer = static_cast(args->NewValue))
+ if (newValue != nullptr)
{
- m_tokenEquationChanged = newer->EquationChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationChanged);
+ m_tokenEquationChanged = newValue->EquationChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationChanged);
- m_tokenEquationStyleChanged = newer->EquationStyleChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationStyleChanged);
+ m_tokenEquationStyleChanged = newValue->EquationStyleChanged += ref new EquationChangedEventHandler(this, &Grapher::OnEquationStyleChanged);
- m_tokenEquationLineEnabledChanged = newer->EquationLineEnabledChanged +=
+ m_tokenEquationLineEnabledChanged = newValue->EquationLineEnabledChanged +=
ref new EquationChangedEventHandler(this, &Grapher::OnEquationLineEnabledChanged);
}
@@ -268,8 +224,9 @@ namespace GraphControl
PlotGraph();
}
- void Grapher::AnalyzeEquation(Equation ^ equation)
+ KeyGraphFeaturesInfo ^ Grapher::AnalyzeEquation(Equation ^ equation)
{
+ auto result = ref new KeyGraphFeaturesInfo();
if (auto graph = GetGraph(equation))
{
if (auto analyzer = graph->GetAnalyzer())
@@ -281,38 +238,17 @@ namespace GraphControl
(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;
- }
+ return KeyGraphFeaturesInfo::Create(functionAnalysisData);
}
}
else
{
- equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisNotSupported;
-
- return;
+ return KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisErrorType::AnalysisNotSupported);
}
}
}
- equation->AnalysisError = CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed;
+ return KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisErrorType::AnalysisCouldNotBePerformed);
}
void Grapher::PlotGraph()
@@ -371,7 +307,7 @@ namespace GraphControl
ss << L",";
}
- ss << eq->GetRequest();
+ ss << eq->GetRequest()->Data();
}
ss << s_getGraphClosingTags;
@@ -463,13 +399,13 @@ namespace GraphControl
}
}
- shared_ptr Grapher::GetGraph(GraphControl::Equation ^ equation)
+ shared_ptr Grapher::GetGraph(Equation ^ equation)
{
std::shared_ptr graph = m_solver->CreateGrapher();
wstringstream ss{};
ss << s_getGraphOpeningTags;
- ss << equation->GetRequest();
+ ss << equation->GetRequest()->Data();
ss << s_getGraphClosingTags;
wstring request = ss.str();
@@ -485,30 +421,6 @@ namespace GraphControl
return nullptr;
}
- IObservableVector ^ Grapher::ConvertWStringVector(vector inVector)
- {
- Vector ^ outVector = ref new Vector();
-
- for (auto v : inVector)
- {
- outVector->Append(ref new String(v.c_str()));
- }
-
- return outVector;
- }
-
- IObservableMap ^ Grapher::ConvertWStringIntMap(map inMap)
- {
- Map ^ outMap = ref new Map();
- ;
- for (auto m : inMap)
- {
- outMap->Insert(ref new String(m.first.c_str()), m.second.ToString());
- }
-
- return outMap;
- }
-
void Grapher::UpdateVariables()
{
auto updatedVariables = ref new Map();
@@ -573,7 +485,7 @@ namespace GraphControl
graphColors.reserve(validEqs.size());
for (Equation ^ eq : validEqs)
{
- auto lineColor = eq->LineColor->Color;
+ auto lineColor = eq->LineColor;
graphColors.emplace_back(lineColor.R, lineColor.G, lineColor.B, lineColor.A);
}
options.SetGraphColors(graphColors);
@@ -595,7 +507,7 @@ namespace GraphControl
return validEqs;
}
- void Grapher::OnForceProportionalAxesChanged(DependencyPropertyChangedEventArgs ^ args)
+ void Grapher::OnForceProportionalAxesPropertyChanged(bool /*oldValue*/, bool /*newValue*/)
{
TryUpdateGraph();
}
diff --git a/src/GraphControl/Control/Grapher.h b/src/GraphControl/Control/Grapher.h
index ebe43eb4..f09f3e79 100644
--- a/src/GraphControl/Control/Grapher.h
+++ b/src/GraphControl/Control/Grapher.h
@@ -4,11 +4,14 @@
#pragma once
#include "DirectX/RenderMain.h"
-#include "Equation.h"
-#include "EquationCollection.h"
+#include "../Models/Equation.h"
+#include "../Models/EquationCollection.h"
+#include "../Utils.h"
#include "IGraphAnalyzer.h"
#include "IMathSolver.h"
#include "Common.h"
+#include "Models/KeyGraphFeaturesInfo.h"
+#include
namespace GraphControl
{
@@ -28,71 +31,13 @@ public
public:
Grapher();
- static void RegisterDependencyProperties();
-
-#pragma region GraphControl::EquationCollection ^ Equations DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ EquationsProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_equationsProperty;
- }
- }
-
- property GraphControl::EquationCollection^ Equations
- {
- GraphControl::EquationCollection^ get()
- {
- return static_cast< GraphControl::EquationCollection^ >(GetValue(s_equationsProperty));
- }
- }
-#pragma endregion
-
-#pragma region Windows::Foundation::Collections::IObservableMap < Platform::String ^, double> ^ Variables DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ VariablesProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_variablesProperty;
- }
- }
-
- property Windows::Foundation::Collections::IObservableMap^ Variables
- {
- Windows::Foundation::Collections::IObservableMap^ get()
- {
- return static_cast^>(GetValue(s_variablesProperty));
- }
-
- void set(Windows::Foundation::Collections::IObservableMap^ value)
- {
- SetValue(s_variablesProperty, value);
- }
- }
-#pragma endregion
-
-#pragma region Windows::UI::Xaml::DataTemplate ^ ForceProportionalAxes DependencyProperty
- static property Windows::UI::Xaml::DependencyProperty^ ForceProportionalAxesTemplateProperty
- {
- Windows::UI::Xaml::DependencyProperty^ get()
- {
- return s_forceProportionalAxesTemplateProperty;
- }
- }
-
- property bool ForceProportionalAxes
- {
- bool get()
- {
- return static_cast(GetValue(s_forceProportionalAxesTemplateProperty));
- }
- void set(bool value)
- {
- SetValue(s_forceProportionalAxesTemplateProperty, value);
- }
- }
-#pragma endregion
-
+ DEPENDENCY_PROPERTY_OWNER(Grapher);
+ DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(bool, ForceProportionalAxes, true);
+ DEPENDENCY_PROPERTY_WITH_DEFAULT(
+ SINGLE_ARG(Windows::Foundation::Collections::IObservableMap ^),
+ Variables,
+ SINGLE_ARG(ref new Platform::Collections::Map()));
+ DEPENDENCY_PROPERTY_R_WITH_DEFAULT_AND_CALLBACK(GraphControl::EquationCollection ^, Equations, nullptr);
// Pass active tracing turned on or off down to the renderer
property bool ActiveTracing
@@ -153,7 +98,7 @@ public
void SetVariable(Platform::String ^ variableName, double newValue);
Platform::String ^ ConvertToLinear(Platform::String ^ mmlString);
void PlotGraph();
- void AnalyzeEquation(GraphControl::Equation ^ equation);
+ GraphControl::KeyGraphFeaturesInfo ^ AnalyzeEquation(GraphControl::Equation ^ equation);
protected:
#pragma region Control Overrides
@@ -173,13 +118,13 @@ public
void OnLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ args);
void OnUnloaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ args);
- static void OnCustomDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
+ void OnForceProportionalAxesPropertyChanged(bool oldValue, bool newValue);
+ void OnEquationsPropertyChanged(EquationCollection ^ oldValue, EquationCollection ^ newValue);
void OnDependencyPropertyChanged(Windows::UI::Xaml::DependencyObject ^ obj, Windows::UI::Xaml::DependencyProperty ^ p);
- void OnEquationsChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
- void OnEquationChanged(GraphControl::Equation ^ equation);
- void OnEquationStyleChanged(GraphControl::Equation ^ equation);
- void OnEquationLineEnabledChanged(GraphControl::Equation ^ equation);
+ void OnEquationChanged(Equation ^ equation);
+ void OnEquationStyleChanged(Equation ^ equation);
+ void OnEquationLineEnabledChanged(Equation ^ equation);
bool TryUpdateGraph();
void TryPlotGraph(bool shouldRetry);
void UpdateGraphOptions(Graphing::IGraphingOptions& options, const std::vector& validEqs);
@@ -188,8 +133,6 @@ public
std::shared_ptr GetGraph(GraphControl::Equation ^ equation);
void UpdateVariables();
- void OnForceProportionalAxesChanged(Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args);
-
void OnBackgroundColorChanged(const Windows::UI::Color& color);
void ScaleRange(double centerX, double centerY, double scale);
@@ -222,8 +165,6 @@ public
Windows::Foundation::EventRegistrationToken m_tokenEquationChanged;
Windows::Foundation::EventRegistrationToken m_tokenEquationLineEnabledChanged;
- static Windows::UI::Xaml::DependencyProperty ^ s_forceProportionalAxesTemplateProperty;
-
Windows::Foundation::EventRegistrationToken m_tokenBackgroundColorChanged;
const std::unique_ptr m_solver;
diff --git a/src/GraphControl/GraphControl.vcxproj b/src/GraphControl/GraphControl.vcxproj
index 251ee35f..b3db6881 100644
--- a/src/GraphControl/GraphControl.vcxproj
+++ b/src/GraphControl/GraphControl.vcxproj
@@ -284,24 +284,27 @@
-
-
+
+
+
+
-
+
+
Create
Create
diff --git a/src/GraphControl/GraphControl.vcxproj.filters b/src/GraphControl/GraphControl.vcxproj.filters
index c0669912..99bf6dd9 100644
--- a/src/GraphControl/GraphControl.vcxproj.filters
+++ b/src/GraphControl/GraphControl.vcxproj.filters
@@ -10,6 +10,9 @@
{e8d91a71-6933-4fd8-b333-421085d13896}
+
+ {0f768477-7ceb-42c4-a32a-cb024320dbc3}
+
@@ -19,9 +22,6 @@
DirectX
-
- Control
-
Control
@@ -31,6 +31,10 @@
DirectX
+
+
+ Models
+
@@ -44,12 +48,6 @@
DirectX
-
- Control
-
-
- Control
-
Control
@@ -59,6 +57,14 @@
DirectX
+
+
+
+ Models
+
+
+ Models
+
@@ -71,5 +77,7 @@
+
+
\ No newline at end of file
diff --git a/src/GraphControl/Models/Equation.cpp b/src/GraphControl/Models/Equation.cpp
new file mode 100644
index 00000000..3ca9313a
--- /dev/null
+++ b/src/GraphControl/Models/Equation.cpp
@@ -0,0 +1,85 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "Equation.h"
+
+using namespace Platform;
+using namespace Platform::Collections;
+using namespace std;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::UI;
+using namespace Windows::UI::ViewManagement;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media;
+
+namespace GraphControl
+{
+ // Remove mml: formatting specific to RichEditBox control, which is not understood by the graph engine.
+ static constexpr wstring_view s_mathPrefix = L"mml:";
+
+ Equation::Equation()
+ {
+ }
+
+ String ^ Equation::GetRequest()
+ {
+ wstringstream ss;
+ wstring expr{ Expression->Data() };
+
+ // Check for unicode characters of less than, less than or equal to, greater than and greater than or equal to.
+ if (expr.find(L">><") != wstring::npos || expr.find(L"><<") != wstring::npos || expr.find(L">≥<") != wstring::npos
+ || expr.find(L">≤<") != wstring::npos)
+ {
+ ss << L"plotIneq2D"s;
+ }
+ else if (expr.find(L">=<") != wstring::npos)
+ {
+ ss << L"plotEq2d";
+ }
+ else
+ {
+ ss << L"plot2d";
+ }
+ ss << GetExpression() << L"";
+
+ return ref new String(ss.str().c_str());
+ }
+
+ wstring Equation::GetExpression()
+ {
+ wstring mathML = Expression->Data();
+
+ size_t mathPrefix = 0;
+ while ((mathPrefix = mathML.find(s_mathPrefix, mathPrefix)) != std::string::npos)
+ {
+ mathML.replace(mathPrefix, s_mathPrefix.length(), L"");
+ mathPrefix += s_mathPrefix.length();
+ }
+
+ return mathML;
+ }
+
+ Color Equation::LineColor::get()
+ {
+ return m_LineColor;
+ }
+ void Equation::LineColor::set(Color value)
+ {
+ if (m_LineColor.R != value.R || m_LineColor.G != value.G || m_LineColor.B != value.B || m_LineColor.A != value.A)
+ {
+ m_LineColor = value;
+ RaisePropertyChanged(L"LineColor");
+ }
+ }
+
+ Platform::String ^ Equation::LineColorPropertyName::get()
+ {
+ return Platform::StringReference(L"LineColor");
+ }
+
+ bool Equation::IsGraphableEquation()
+ {
+ return !Expression->IsEmpty() && IsLineEnabled && !HasGraphError;
+ }
+}
diff --git a/src/GraphControl/Models/Equation.h b/src/GraphControl/Models/Equation.h
new file mode 100644
index 00000000..cc404b7e
--- /dev/null
+++ b/src/GraphControl/Models/Equation.h
@@ -0,0 +1,41 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Utils.h"
+#include
+
+namespace GraphControl
+{
+ [Windows::UI::Xaml::Data::Bindable] public ref class Equation sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
+ {
+ public:
+ Equation();
+
+ OBSERVABLE_OBJECT();
+ OBSERVABLE_NAMED_PROPERTY_RW(Platform::String ^, Expression);
+ OBSERVABLE_NAMED_PROPERTY_RW(bool, IsLineEnabled);
+ OBSERVABLE_NAMED_PROPERTY_RW(bool, IsValidated);
+ OBSERVABLE_NAMED_PROPERTY_RW(bool, HasGraphError);
+
+ property Windows::UI::Color LineColor
+ {
+ Windows::UI::Color get();
+ void set(Windows::UI::Color value);
+ }
+
+ static property Platform::String
+ ^ LineColorPropertyName { Platform::String ^ get(); }
+
+ public : Platform::String
+ ^ GetRequest();
+
+ bool IsGraphableEquation();
+
+ private:
+ std::wstring GetExpression();
+
+ private:
+ Windows::UI::Color m_LineColor;
+ };
+}
diff --git a/src/GraphControl/Control/EquationCollection.h b/src/GraphControl/Models/EquationCollection.h
similarity index 77%
rename from src/GraphControl/Control/EquationCollection.h
rename to src/GraphControl/Models/EquationCollection.h
index dc920c6a..d1e1ba18 100644
--- a/src/GraphControl/Control/EquationCollection.h
+++ b/src/GraphControl/Models/EquationCollection.h
@@ -38,7 +38,7 @@ public
{
m_vector->Append(value);
m_tokens.emplace_back(
- value->PropertyChanged += ref new GraphControl::PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged));
+ value->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged));
}
virtual void Clear()
@@ -75,7 +75,8 @@ public
{
m_vector->InsertAt(index, value);
m_tokens.insert(
- m_tokens.begin() + index, value->PropertyChanged += ref new PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged));
+ m_tokens.begin() + index,
+ value->PropertyChanged += ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged));
}
virtual void RemoveAt(unsigned int index)
@@ -110,7 +111,8 @@ public
m_tokens.resize(size);
for (auto i = 0u; i < size; i++)
{
- m_tokens[i] = items[i]->PropertyChanged += ref new PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged);
+ m_tokens[i] = items[i]->PropertyChanged +=
+ ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged);
}
m_vector->ReplaceAll(items);
@@ -121,7 +123,8 @@ public
m_vector->GetAt(index)->PropertyChanged -= m_tokens[index];
m_vector->SetAt(index, value);
- m_tokens[index] = value->PropertyChanged += ref new PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged);
+ m_tokens[index] = value->PropertyChanged +=
+ ref new Windows::UI::Xaml::Data::PropertyChangedEventHandler(this, &EquationCollection::OnEquationPropertyChanged);
}
#pragma endregion
@@ -151,19 +154,21 @@ public
event EquationChangedEventHandler ^ EquationLineEnabledChanged;
private:
- void OnEquationPropertyChanged(GraphControl::Equation ^ sender, Platform::String ^ propertyName)
+ void OnEquationPropertyChanged(Object^ sender, Windows::UI::Xaml::Data::PropertyChangedEventArgs ^ args)
{
- if (propertyName == EquationProperties::LineColor)
+ auto equation = static_cast(sender);
+ auto propertyName = args->PropertyName;
+ if (propertyName == GraphControl::Equation::LineColorPropertyName)
{
- EquationStyleChanged(sender);
+ EquationStyleChanged(equation);
}
- else if (propertyName == EquationProperties::Expression)
+ else if (propertyName == GraphControl::Equation::ExpressionPropertyName)
{
- EquationChanged(sender);
+ EquationChanged(equation);
}
- else if (propertyName == EquationProperties::IsLineEnabled)
+ else if (propertyName == GraphControl::Equation::IsLineEnabledPropertyName)
{
- EquationLineEnabledChanged(sender);
+ EquationLineEnabledChanged(equation);
}
}
diff --git a/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp b/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp
new file mode 100644
index 00000000..c7552246
--- /dev/null
+++ b/src/GraphControl/Models/KeyGraphFeaturesInfo.cpp
@@ -0,0 +1,70 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#include "pch.h"
+#include "KeyGraphFeaturesInfo.h"
+#include "../../CalcViewModel/GraphingCalculatorEnums.h"
+
+using namespace Platform;
+using namespace Platform::Collections;
+using namespace std;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::UI;
+using namespace Windows::UI::ViewManagement;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Media;
+using namespace GraphControl;
+using namespace Graphing;
+
+IObservableVector ^ KeyGraphFeaturesInfo::ConvertWStringVector(vector inVector)
+{
+ auto outVector = ref new Vector();
+
+ for (auto v : inVector)
+ {
+ outVector->Append(ref new String(v.c_str()));
+ }
+
+ return outVector;
+}
+
+IObservableMap ^ KeyGraphFeaturesInfo::ConvertWStringIntMap(map inMap)
+{
+ Map ^ outMap = ref new Map();
+ ;
+ for (auto m : inMap)
+ {
+ outMap->Insert(ref new String(m.first.c_str()), m.second.ToString());
+ }
+
+ return outMap;
+}
+
+KeyGraphFeaturesInfo ^ KeyGraphFeaturesInfo::Create(IGraphFunctionAnalysisData data)
+{
+ auto res = ref new KeyGraphFeaturesInfo();
+ res->XIntercept = ref new String(data.Zeros.c_str());
+ res->YIntercept = ref new String(data.YIntercept.c_str());
+ res->Domain = ref new String(data.Domain.c_str());
+ res->Range = ref new String(data.Range.c_str());
+ res->Parity = data.Parity;
+ res->PeriodicityDirection = data.PeriodicityDirection;
+ res->PeriodicityExpression = ref new String(data.PeriodicityExpression.c_str());
+ res->Minima = ConvertWStringVector(data.Minima);
+ res->Maxima = ConvertWStringVector(data.Maxima);
+ res->InflectionPoints = ConvertWStringVector(data.InflectionPoints);
+ res->Monotonicity = ConvertWStringIntMap(data.MonotoneIntervals);
+ res->VerticalAsymptotes = ConvertWStringVector(data.VerticalAsymptotes);
+ res->HorizontalAsymptotes = ConvertWStringVector(data.HorizontalAsymptotes);
+ res->ObliqueAsymptotes = ConvertWStringVector(data.ObliqueAsymptotes);
+ res->TooComplexFeatures = data.TooComplexFeatures;
+ res->AnalysisError = CalculatorApp::AnalysisErrorType::NoError;
+ return res;
+}
+
+KeyGraphFeaturesInfo ^ KeyGraphFeaturesInfo::Create(CalculatorApp::AnalysisErrorType type)
+{
+ auto res = ref new KeyGraphFeaturesInfo();
+ res->AnalysisError = type;
+ return res;
+}
diff --git a/src/GraphControl/Models/KeyGraphFeaturesInfo.h b/src/GraphControl/Models/KeyGraphFeaturesInfo.h
new file mode 100644
index 00000000..2d389a0e
--- /dev/null
+++ b/src/GraphControl/Models/KeyGraphFeaturesInfo.h
@@ -0,0 +1,51 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+#include "Utils.h"
+
+
+namespace Graphing
+{
+ struct IGraphFunctionAnalysisData;
+}
+
+namespace CalculatorApp
+{
+ enum AnalysisErrorType;
+}
+
+namespace GraphControl
+{
+
+public
+ ref class KeyGraphFeaturesInfo sealed
+ {
+ public:
+ PROPERTY_R(Platform::String ^, XIntercept);
+ PROPERTY_R(Platform::String ^, YIntercept);
+ PROPERTY_R(int, Parity);
+ PROPERTY_R(int, PeriodicityDirection);
+ PROPERTY_R(Platform::String ^, PeriodicityExpression);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, Minima);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, Maxima);
+ PROPERTY_R(Platform::String ^, Domain);
+ PROPERTY_R(Platform::String ^, Range);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, InflectionPoints);
+ PROPERTY_R(SINGLE_ARG(Windows::Foundation::Collections::IObservableMap ^), Monotonicity);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, VerticalAsymptotes);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, HorizontalAsymptotes);
+ PROPERTY_R(Windows::Foundation::Collections::IVector ^, ObliqueAsymptotes);
+ PROPERTY_R(int, TooComplexFeatures);
+ PROPERTY_R(int, AnalysisError);
+
+ internal:
+ static KeyGraphFeaturesInfo ^ Create(Graphing::IGraphFunctionAnalysisData data);
+ static KeyGraphFeaturesInfo ^ Create(CalculatorApp::AnalysisErrorType type);
+
+ private:
+ static Windows::Foundation::Collections::IObservableVector ^ ConvertWStringVector(std::vector inVector);
+ static Windows::Foundation::Collections::
+ IObservableMap ^ ConvertWStringIntMap(std::map inMap);
+ };
+}
diff --git a/src/GraphControl/Utils.h b/src/GraphControl/Utils.h
new file mode 100644
index 00000000..e29e4bde
--- /dev/null
+++ b/src/GraphControl/Utils.h
@@ -0,0 +1,588 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+#pragma once
+
+// Utility macros to make Models easier to write
+// generates a member variable called m_
+
+#define SINGLE_ARG(...) __VA_ARGS__
+
+#define PROPERTY_R(t, n) \
+ property t n \
+ { \
+ t get() \
+ { \
+ return m_##n; \
+ } \
+ \
+ private: \
+ void set(t value) \
+ { \
+ m_##n = value; \
+ } \
+ } \
+ \
+private: \
+ t m_##n; \
+ \
+public:
+
+#define PROPERTY_RW(t, n) \
+ property t n \
+ { \
+ t get() \
+ { \
+ return m_##n; \
+ } \
+ void set(t value) \
+ { \
+ m_##n = value; \
+ } \
+ } \
+ \
+private: \
+ t m_##n; \
+ \
+public:
+
+#define OBSERVABLE_PROPERTY_R(t, n) \
+ property t n \
+ { \
+ t get() \
+ { \
+ return m_##n; \
+ } \
+ \
+ private: \
+ void set(t value) \
+ { \
+ if (m_##n != value) \
+ { \
+ m_##n = value; \
+ RaisePropertyChanged(L#n); \
+ } \
+ } \
+ } \
+ \
+private: \
+ t m_##n; \
+ \
+public:
+
+#define OBSERVABLE_PROPERTY_RW(t, n) \
+ property t n \
+ { \
+ t get() \
+ { \
+ return m_##n; \
+ } \
+ void set(t value) \
+ { \
+ if (m_##n != value) \
+ { \
+ m_##n = value; \
+ RaisePropertyChanged(L#n); \
+ } \
+ } \
+ } \
+ \
+private: \
+ t m_##n; \
+ \
+public:
+
+#define OBSERVABLE_NAMED_PROPERTY_R(t, n) \
+ OBSERVABLE_PROPERTY_R(t, n) \
+ internal: \
+ static property Platform::String ^ n##PropertyName \
+ { \
+ Platform::String ^ get() { return Platform::StringReference(L#n); } \
+ } \
+ \
+public:
+
+#define OBSERVABLE_NAMED_PROPERTY_RW(t, n) \
+ OBSERVABLE_PROPERTY_RW(t, n) \
+ internal: \
+ static property Platform::String ^ n##PropertyName \
+ { \
+ Platform::String ^ get() { return Platform::StringReference(L#n); } \
+ } \
+ \
+public:
+
+#define OBSERVABLE_PROPERTY_FIELD(n) m_##n
+
+// This variant of the observable object is for objects that don't want to react to property changes
+#ifndef UNIT_TESTS
+#define OBSERVABLE_OBJECT() \
+ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \
+ internal: \
+ void RaisePropertyChanged(Platform::String ^ p) \
+ { \
+ PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \
+ } \
+ \
+public:
+#else
+#define OBSERVABLE_OBJECT() \
+ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \
+ internal: \
+ void RaisePropertyChanged(Platform::String ^ p) \
+ { \
+ } \
+ \
+public:
+#endif
+
+// The callback specified in the macro is a method in the class that will be called every time the object changes
+// the callback is supposed to be have a single parameter of type Platform::String^
+#ifndef UNIT_TESTS
+#define OBSERVABLE_OBJECT_CALLBACK(c) \
+ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \
+ internal: \
+ void RaisePropertyChanged(Platform::String ^ p) \
+ { \
+ PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(p)); \
+ c(p); \
+ } \
+ \
+public:
+#else
+#define OBSERVABLE_OBJECT_CALLBACK(c) \
+ virtual event Windows::UI::Xaml::Data::PropertyChangedEventHandler ^ PropertyChanged; \
+ internal: \
+ void RaisePropertyChanged(Platform::String ^ p) \
+ { \
+ c(p); \
+ } \
+ \
+public:
+#endif
+
+// The variable member generated by this macro should not be used in the class code, use the
+// property getter instead.
+#define COMMAND_FOR_METHOD(p, m) \
+ property Windows::UI::Xaml::Input::ICommand^ p {\
+ Windows::UI::Xaml::Input::ICommand^ get() {\
+ if (!donotuse_##p) {\
+ donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\
+ } return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; \
+ \
+public:
+
+// Utilities for DependencyProperties
+namespace Utils
+{
+ namespace Details
+ {
+ template
+ struct IsRefClass
+ {
+ static const bool value = __is_ref_class(T);
+ };
+
+ template
+ struct RemoveHat
+ {
+ typedef T type;
+ };
+
+ template
+ struct RemoveHat
+ {
+ typedef T type;
+ };
+
+ template
+ typename std::enable_if::value, T ^>::type MakeDefault()
+ {
+ return nullptr;
+ }
+
+ template
+ typename std::enable_if::value, T>::type MakeDefault()
+ {
+ return T();
+ }
+
+ // There's a bug in Xaml in which custom enums are not recognized by the property system/binding
+ // therefore this template will determine that for enums the type to use to register the
+ // DependencyProperty is to be Object, for everything else it will use the type
+ // NOTE: If we are to find more types in which this is broken this template
+ // will be specialized for those types to return Object
+ template
+ struct TypeToUseForDependencyProperty
+ {
+ typedef typename std::conditional::value, Platform::Object, T>::type type;
+ };
+ }
+
+ const wchar_t LRE = 0x202a; // Left-to-Right Embedding
+ const wchar_t PDF = 0x202c; // Pop Directional Formatting
+ const wchar_t LRO = 0x202d; // Left-to-Right Override
+
+ // Regular DependencyProperty
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(
+ _In_ const wchar_t* const name,
+ _In_ Windows::UI::Xaml::PropertyMetadata^ metadata)
+ {
+ typedef typename Details::RemoveHat::type OwnerType;
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType;
+
+ static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class");
+
+ return Windows::UI::Xaml::DependencyProperty::Register(
+ Platform::StringReference(name),
+ ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type
+ OwnerType::typeid,
+ metadata);
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+
+ return RegisterDependencyProperty(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault()));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyProperty(_In_ const wchar_t* const name, TType defaultValue)
+ {
+ return RegisterDependencyProperty(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(defaultValue));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback(
+ _In_ wchar_t const * const name,
+ TCallback callback)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ return RegisterDependencyProperty(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(
+ Details::MakeDefault(),
+ ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyWithCallback(
+ _In_ wchar_t const * const name,
+ TType defaultValue,
+ TCallback callback)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ return RegisterDependencyProperty(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(
+ defaultValue,
+ ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
+ }
+
+ // Attached DependencyProperty
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(
+ _In_ const wchar_t* const name,
+ _In_ Windows::UI::Xaml::PropertyMetadata^ metadata)
+ {
+ typedef typename Details::RemoveHat::type OwnerType;
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ typedef typename Details::TypeToUseForDependencyProperty::type ThisDependencyPropertyType;
+
+ static_assert(Details::IsRefClass::value, "The owner of a DependencyProperty must be a ref class");
+
+ return Windows::UI::Xaml::DependencyProperty::RegisterAttached(
+ Platform::StringReference(name),
+ ThisDependencyPropertyType::typeid, // Work around bugs in Xaml by using the filtered type
+ OwnerType::typeid,
+ metadata);
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ return RegisterDependencyPropertyAttached(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(Details::MakeDefault()));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttached(_In_ const wchar_t* const name, TType defaultValue)
+ {
+ return RegisterDependencyPropertyAttached(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(defaultValue));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback(
+ _In_ wchar_t const * const name,
+ TCallback callback)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ return RegisterDependencyPropertyAttached(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(
+ Details::MakeDefault(),
+ ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
+ }
+
+ template
+ Windows::UI::Xaml::DependencyProperty^ RegisterDependencyPropertyAttachedWithCallback(
+ _In_ wchar_t const * const name,
+ TType defaultValue,
+ TCallback callback)
+ {
+ typedef typename Details::RemoveHat::type ThisPropertyType;
+ return RegisterDependencyPropertyAttached(
+ name,
+ ref new Windows::UI::Xaml::PropertyMetadata(
+ defaultValue,
+ ref new Windows::UI::Xaml::PropertyChangedCallback(callback)));
+ }
+
+ template
+ void Swap(T *ref1, T *ref2)
+ {
+ T temp = *ref1;
+ *ref1 = *ref2;
+ *ref2 = temp;
+ }
+}
+
+// This goes into the header to define the property, in the public: section of the class
+#define DEPENDENCY_PROPERTY_OWNER(owner) \
+private: \
+ typedef owner DependencyPropertiesOwner; \
+ \
+public:
+
+// Normal DependencyProperty
+#define DEPENDENCY_PROPERTY(type, name) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyProperty(L#name); \
+ } \
+ \
+public:
+
+#define DEPENDENCY_PROPERTY_WITH_CALLBACK(type, name) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyPropertyWithCallback(L#name, &On##name##PropertyChangedImpl); \
+ } \
+ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \
+ { \
+ auto self = safe_cast(sender); \
+ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \
+ } \
+ \
+public:
+#define DEPENDENCY_PROPERTY_WITH_DEFAULT(type, name, defaultValue) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyProperty(L#name, defaultValue); \
+ } \
+ \
+public:
+
+#define DEPENDENCY_PROPERTY_WITH_CALLBACK(type, name) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyPropertyWithCallback(L#name, &On##name##PropertyChangedImpl); \
+ } \
+ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \
+ { \
+ auto self = safe_cast(sender); \
+ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \
+ } \
+ \
+public:
+
+#define DEPENDENCY_PROPERTY_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyPropertyWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \
+ } \
+ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \
+ { \
+ auto self = safe_cast(sender); \
+ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \
+ } \
+ \
+public:
+
+#define DEPENDENCY_PROPERTY_R_WITH_DEFAULT_AND_CALLBACK(type, name, defaultValue) \
+ property type name \
+ { \
+ type get() \
+ { \
+ return safe_cast(GetValue(s_##name##Property)); \
+ } \
+ private: void set(type value) \
+ { \
+ SetValue(s_##name##Property, value); \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ s_##name##Property; \
+ \
+public: \
+ static property Windows::UI::Xaml::DependencyProperty ^ name##Property \
+ { \
+ Windows::UI::Xaml::DependencyProperty ^ get() { \
+ assert(s_##name##Property); \
+ return s_##name##Property; \
+ } \
+ } \
+ \
+private: \
+ static Windows::UI::Xaml::DependencyProperty ^ Initialize##name##Property() \
+ { \
+ return Utils::RegisterDependencyPropertyWithCallback(L#name, defaultValue, &On##name##PropertyChangedImpl); \
+ } \
+ static void On##name##PropertyChangedImpl(Windows::UI::Xaml::DependencyObject ^ sender, Windows::UI::Xaml::DependencyPropertyChangedEventArgs ^ args) \
+ { \
+ auto self = safe_cast(sender); \
+ self->On##name##PropertyChanged(safe_cast(args->OldValue), safe_cast(args->NewValue)); \
+ } \
+ \
+public:
+
+// This goes into the cpp to initialize the static variable
+#define DEPENDENCY_PROPERTY_INITIALIZATION(owner, name) Windows::UI::Xaml::DependencyProperty ^ owner::s_##name##Property = owner::Initialize##name##Property();
diff --git a/src/GraphControl/pch.h b/src/GraphControl/pch.h
index faf9c722..28613840 100644
--- a/src/GraphControl/pch.h
+++ b/src/GraphControl/pch.h
@@ -18,6 +18,10 @@
#include
#include
#include
+#include
+#include