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

* refactor code

* update KGF

* Rename some functions

* Undo comment out of proj file

* Pr feedback
This commit is contained in:
Pepe Rivera 2019-11-20 14:28:32 -08:00 committed by GitHub
parent 9ee2f8a293
commit 288a90e0fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 215 additions and 764 deletions

View File

@ -413,6 +413,9 @@
<ProjectReference Include="..\CalcManager\CalcManager.vcxproj">
<Project>{311e866d-8b93-4609-a691-265941fee101}</Project>
</ProjectReference>
<ProjectReference Include="..\GraphControl\GraphControl.vcxproj">
<Project>{e727a92b-f149-492c-8117-c039a298719b}</Project>
</ProjectReference>
</ItemGroup>
<ItemDefinitionGroup Condition="!Exists('DataLoaders\DataLoaderConstants.h')">
<ClCompile>

View File

@ -14,6 +14,7 @@ using namespace std;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::Foundation::Collections;
using namespace GraphControl;
namespace CalculatorApp::ViewModel
{
@ -31,83 +32,62 @@ namespace CalculatorApp::ViewModel
{
}
EquationViewModel::EquationViewModel()
: m_LineColor{ nullptr }
, m_Expression{ "" }
, m_IsAnalysisUpdated{ false }
, m_Domain{ "" }
, m_Range{ "" }
, m_XIntercept{ "" }
, m_YIntercept{ "" }
, m_Parity{ -1 }
, m_PeriodicityDirection{ -1 }
, m_PeriodicityExpression{ "" }
, m_Minima{ ref new Vector<String ^>() }
, m_Maxima{ ref new Vector<String ^>() }
, m_InflectionPoints{ ref new Vector<String ^>() }
, m_Monotonicity{ ref new Map<String ^, String ^>() }
, m_VerticalAsymptotes{ ref new Vector<String ^>() }
, m_HorizontalAsymptotes{ ref new Vector<String ^>() }
, m_ObliqueAsymptotes{ ref new Vector<String ^>() }
, m_TooComplexFeatures{ -1 }
, m_AnalysisError{ 0 }
, m_AnalysisErrorVisible{ false }
EquationViewModel::EquationViewModel(GraphControl::Equation ^ equation)
: m_AnalysisErrorVisible{ false }
, m_KeyGraphFeaturesItems{ ref new Vector<KeyGraphFeaturesItem ^>() }
, m_resourceLoader{ Windows::ApplicationModel::Resources::ResourceLoader::GetForCurrentView() }
{
}
void EquationViewModel::OnPropertyChanged(String ^ propertyName)
{
if (propertyName == L"IsAnalysisUpdated")
if (equation == nullptr)
{
OnIsAnalysisUpdatedChanged();
throw ref new InvalidArgumentException(L"Equation cannot be null");
}
GraphEquation = equation;
}
void EquationViewModel::OnIsAnalysisUpdatedChanged()
void EquationViewModel::PopulateKeyGraphFeatures()
{
if (IsAnalysisUpdated)
if (GraphEquation->AnalysisError != 0)
{
if (AnalysisError != 0)
AnalysisErrorVisible = true;
if (GraphEquation->AnalysisError == static_cast<int>(AnalysisErrorType::AnalysisCouldNotBePerformed))
{
AnalysisErrorVisible = true;
if (AnalysisError == static_cast<int>(AnalysisErrorType::AnalysisCouldNotBePerformed))
{
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisCouldNotBePerformed");
}
else if (AnalysisError == static_cast<int>(AnalysisErrorType::AnalysisNotSupported))
{
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisNotSupported");
}
return;
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisCouldNotBePerformed");
}
KeyGraphFeaturesItems->Clear();
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Domain"), Domain, m_resourceLoader->GetString(L"KGFDomainNone"));
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Range"), Range, m_resourceLoader->GetString(L"KGFRangeNone"));
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"XIntercept"), XIntercept, m_resourceLoader->GetString(L"KGFXInterceptNone"));
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"YIntercept"), YIntercept, m_resourceLoader->GetString(L"KGFYInterceptNone"));
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Minima"), Minima, m_resourceLoader->GetString(L"KGFMinimaNone"));
SetKeyGraphFeaturesItems(m_resourceLoader->GetString(L"Maxima"), Maxima, m_resourceLoader->GetString(L"KGFMaximaNone"));
SetKeyGraphFeaturesItems(
m_resourceLoader->GetString(L"InflectionPoints"), InflectionPoints, m_resourceLoader->GetString(L"KGFInflectionPointsNone"));
SetKeyGraphFeaturesItems(
m_resourceLoader->GetString(L"VerticalAsymptotes"), VerticalAsymptotes, m_resourceLoader->GetString(L"KGFVerticalAsymptotesNone"));
SetKeyGraphFeaturesItems(
m_resourceLoader->GetString(L"HorizontalAsymptotes"), HorizontalAsymptotes, m_resourceLoader->GetString(L"KGFHorizontalAsymptotesNone"));
SetKeyGraphFeaturesItems(
m_resourceLoader->GetString(L"ObliqueAsymptotes"), ObliqueAsymptotes, m_resourceLoader->GetString(L"KGFObliqueAsymptotesNone"));
SetParityStringProperty();
SetPeriodicityStringProperty();
SetMonotoncityStringProperty();
SetTooComplexFeaturesErrorProperty();
AnalysisErrorVisible = false;
IsAnalysisUpdated = false;
else if (GraphEquation->AnalysisError == static_cast<int>(AnalysisErrorType::AnalysisNotSupported))
{
AnalysisErrorString = m_resourceLoader->GetString(L"KGFAnalysisNotSupported");
}
return;
}
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"InflectionPoints"), GraphEquation->InflectionPoints, m_resourceLoader->GetString(L"KGFInflectionPointsNone"));
AddKeyGraphFeature(
m_resourceLoader->GetString(L"VerticalAsymptotes"), GraphEquation->VerticalAsymptotes, m_resourceLoader->GetString(L"KGFVerticalAsymptotesNone"));
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();
AnalysisErrorVisible = false;
}
void EquationViewModel::SetKeyGraphFeaturesItems(String ^ title, String ^ expression, String ^ errorString)
void EquationViewModel::AddKeyGraphFeature(String ^ title, String ^ expression, String ^ errorString)
{
KeyGraphFeaturesItem ^ item = ref new KeyGraphFeaturesItem();
item->Title = title;
@ -124,7 +104,7 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(item);
}
void EquationViewModel::SetKeyGraphFeaturesItems(String ^ title, IObservableVector<String ^> ^ expressionVector, String ^ errorString)
void EquationViewModel::AddKeyGraphFeature(String ^ title, IVector<String ^> ^ expressionVector, String ^ errorString)
{
KeyGraphFeaturesItem ^ item = ref new KeyGraphFeaturesItem();
item->Title = title;
@ -144,11 +124,11 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(item);
}
void EquationViewModel::SetParityStringProperty()
void EquationViewModel::AddParityKeyGraphFeature()
{
KeyGraphFeaturesItem ^ parityItem = ref new KeyGraphFeaturesItem();
parityItem->Title = m_resourceLoader->GetString(L"Parity");
switch (Parity)
switch (GraphEquation->Parity)
{
case 0:
parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityUnknown"));
@ -164,18 +144,17 @@ namespace CalculatorApp::ViewModel
break;
default:
parityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFParityUnknown"));
}
parityItem->IsText = true;
KeyGraphFeaturesItems->Append(parityItem);
}
void EquationViewModel::SetPeriodicityStringProperty()
void EquationViewModel::AddPeriodicityKeyGraphFeature()
{
KeyGraphFeaturesItem ^ periodicityItem = ref new KeyGraphFeaturesItem();
periodicityItem->Title = m_resourceLoader->GetString(L"Periodicity");
switch (PeriodicityDirection)
switch (GraphEquation->PeriodicityDirection)
{
case 0:
// Periodicity is not supported or is too complex to calculate.
@ -183,14 +162,14 @@ namespace CalculatorApp::ViewModel
// SetTooComplexFeaturesErrorProperty will set the too complex error when periodicity is supported and unknown
return;
case 1:
if (PeriodicityExpression == L"")
if (GraphEquation->PeriodicityExpression == L"")
{
periodicityItem->DisplayItems->Append(m_resourceLoader->GetString(L"KGFPeriodicityUnknown"));
periodicityItem->IsText = true;
}
else
{
periodicityItem->DisplayItems->Append(PeriodicityExpression);
periodicityItem->DisplayItems->Append(GraphEquation->PeriodicityExpression);
periodicityItem->IsText = false;
}
break;
@ -206,13 +185,13 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(periodicityItem);
}
void EquationViewModel::SetMonotoncityStringProperty()
void EquationViewModel::AddMonotoncityKeyGraphFeature()
{
KeyGraphFeaturesItem ^ monotonicityItem = ref new KeyGraphFeaturesItem();
monotonicityItem->Title = m_resourceLoader->GetString(L"Monotonicity");
if (Monotonicity->Size != 0)
if (GraphEquation->Monotonicity->Size != 0)
{
for (auto item : Monotonicity)
for (auto item : GraphEquation->Monotonicity)
{
GridDisplayItems ^ gridItem = ref new GridDisplayItems();
gridItem->Expression = item->Key;
@ -250,9 +229,9 @@ namespace CalculatorApp::ViewModel
KeyGraphFeaturesItems->Append(monotonicityItem);
}
void EquationViewModel::SetTooComplexFeaturesErrorProperty()
void EquationViewModel::AddTooComplexKeyGraphFeature()
{
if (TooComplexFeatures <= 0)
if (GraphEquation->TooComplexFeatures <= 0)
{
return;
}
@ -260,55 +239,55 @@ namespace CalculatorApp::ViewModel
Platform::String ^ separator = ref new String(LocalizationSettings::GetInstance().GetListSeparator().c_str());
wstring error;
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Domain) == KeyGraphFeaturesFlag::Domain)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Domain) == KeyGraphFeaturesFlag::Domain)
{
error.append((m_resourceLoader->GetString(L"Domain") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Range) == KeyGraphFeaturesFlag::Range)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Range) == KeyGraphFeaturesFlag::Range)
{
error.append((m_resourceLoader->GetString(L"Range") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Zeros) == KeyGraphFeaturesFlag::Zeros)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Zeros) == KeyGraphFeaturesFlag::Zeros)
{
error.append((m_resourceLoader->GetString(L"XIntercept") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::YIntercept) == KeyGraphFeaturesFlag::YIntercept)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::YIntercept) == KeyGraphFeaturesFlag::YIntercept)
{
error.append((m_resourceLoader->GetString(L"YIntercept") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Parity) == KeyGraphFeaturesFlag::Parity)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Parity) == KeyGraphFeaturesFlag::Parity)
{
error.append((m_resourceLoader->GetString(L"Parity") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Periodicity) == KeyGraphFeaturesFlag::Periodicity)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Periodicity) == KeyGraphFeaturesFlag::Periodicity)
{
error.append((m_resourceLoader->GetString(L"Periodicity") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Minima) == KeyGraphFeaturesFlag::Minima)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Minima) == KeyGraphFeaturesFlag::Minima)
{
error.append((m_resourceLoader->GetString(L"Minima") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::Maxima) == KeyGraphFeaturesFlag::Maxima)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::Maxima) == KeyGraphFeaturesFlag::Maxima)
{
error.append((m_resourceLoader->GetString(L"Maxima") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::InflectionPoints) == KeyGraphFeaturesFlag::InflectionPoints)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::InflectionPoints) == KeyGraphFeaturesFlag::InflectionPoints)
{
error.append((m_resourceLoader->GetString(L"InflectionPoints") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::VerticalAsymptotes) == KeyGraphFeaturesFlag::VerticalAsymptotes)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::VerticalAsymptotes) == KeyGraphFeaturesFlag::VerticalAsymptotes)
{
error.append((m_resourceLoader->GetString(L"VerticalAsymptotes") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::HorizontalAsymptotes) == KeyGraphFeaturesFlag::HorizontalAsymptotes)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::HorizontalAsymptotes) == KeyGraphFeaturesFlag::HorizontalAsymptotes)
{
error.append((m_resourceLoader->GetString(L"HorizontalAsymptotes") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::ObliqueAsymptotes) == KeyGraphFeaturesFlag::ObliqueAsymptotes)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::ObliqueAsymptotes) == KeyGraphFeaturesFlag::ObliqueAsymptotes)
{
error.append((m_resourceLoader->GetString(L"ObliqueAsymptotes") + separator + L" ")->Data());
}
if ((TooComplexFeatures & KeyGraphFeaturesFlag::MonotoneIntervals) == KeyGraphFeaturesFlag::MonotoneIntervals)
if ((GraphEquation->TooComplexFeatures & KeyGraphFeaturesFlag::MonotoneIntervals) == KeyGraphFeaturesFlag::MonotoneIntervals)
{
error.append((m_resourceLoader->GetString(L"Monotonicity") + separator + L" ")->Data());
}

View File

@ -36,58 +36,60 @@ public
ref class EquationViewModel sealed : public Windows::UI::Xaml::Data::INotifyPropertyChanged
{
public:
EquationViewModel();
EquationViewModel(GraphControl::Equation ^ equation);
OBSERVABLE_OBJECT_CALLBACK(OnPropertyChanged);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Expression);
OBSERVABLE_PROPERTY_RW(Windows::UI::Xaml::Media::SolidColorBrush ^, LineColor);
OBSERVABLE_OBJECT();
OBSERVABLE_PROPERTY_R(GraphControl::Equation ^, GraphEquation);
// Key Graph Features
OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(bool, IsAnalysisUpdated);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Domain);
OBSERVABLE_PROPERTY_RW(Platform::String ^, Range);
OBSERVABLE_PROPERTY_RW(Platform::String ^, XIntercept);
OBSERVABLE_PROPERTY_RW(Platform::String ^, YIntercept);
OBSERVABLE_PROPERTY_RW(int, Parity);
OBSERVABLE_PROPERTY_RW(int, PeriodicityDirection);
OBSERVABLE_PROPERTY_RW(Platform::String ^, PeriodicityExpression);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, Minima);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, Maxima);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, InflectionPoints);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, VerticalAsymptotes);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, HorizontalAsymptotes);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^, ObliqueAsymptotes);
OBSERVABLE_PROPERTY_RW(int, TooComplexFeatures);
OBSERVABLE_PROPERTY_RW(int, AnalysisError);
OBSERVABLE_PROPERTY_R(Platform::String ^, AnalysisErrorString);
OBSERVABLE_PROPERTY_R(bool, AnalysisErrorVisible);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::KeyGraphFeaturesItem ^> ^, KeyGraphFeaturesItems)
property Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String^> ^ Monotonicity
property Platform::String ^ Expression
{
Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String^> ^ get()
Platform::String ^ get()
{
return m_Monotonicity;
return GraphEquation->Expression;
}
void set(Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String^> ^ value)
void set(Platform::String ^ value)
{
if (m_Monotonicity != value)
if (GraphEquation->Expression != value)
{
m_Monotonicity = value;
GraphEquation->Expression = value;
RaisePropertyChanged("Expression");
}
}
}
property Windows::UI::Xaml::Media::SolidColorBrush ^ LineColor
{
Windows::UI::Xaml::Media::SolidColorBrush ^ get()
{
return GraphEquation->LineColor;
}
void set(Windows::UI::Xaml::Media::SolidColorBrush ^ value)
{
if (GraphEquation->LineColor != value)
{
GraphEquation->LineColor = value;
RaisePropertyChanged("LineColor");
}
}
}
// Key Graph Features
OBSERVABLE_PROPERTY_R(Platform::String ^, AnalysisErrorString);
OBSERVABLE_PROPERTY_R(bool, AnalysisErrorVisible);
OBSERVABLE_PROPERTY_R(Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::KeyGraphFeaturesItem ^> ^, KeyGraphFeaturesItems)
void PopulateKeyGraphFeatures();
private:
void OnPropertyChanged(Platform::String ^ propertyName);
void SetParityStringProperty();
void SetPeriodicityStringProperty();
void SetKeyGraphFeaturesItems(Platform::String ^ title, Platform::String ^ expression, Platform::String ^ errorString);
void SetKeyGraphFeaturesItems(Platform::String ^ title, Windows::Foundation::Collections::IObservableVector<Platform::String ^> ^ expressionVector,
void AddKeyGraphFeature(Platform::String ^ title, Platform::String ^ expression, Platform::String ^ errorString);
void AddKeyGraphFeature(
Platform::String ^ title,
Windows::Foundation::Collections::IVector<Platform::String ^> ^ expressionVector,
Platform::String ^ errorString);
void SetMonotoncityStringProperty();
void SetTooComplexFeaturesErrorProperty();
void OnIsAnalysisUpdatedChanged();
void AddParityKeyGraphFeature();
void AddPeriodicityKeyGraphFeature();
void AddMonotoncityKeyGraphFeature();
void AddTooComplexKeyGraphFeature();
Windows::Foundation::Collections::IObservableMap<Platform::String ^, Platform::String ^> ^ m_Monotonicity;
Windows::ApplicationModel::Resources::ResourceLoader ^ m_resourceLoader;

View File

@ -63,7 +63,7 @@ void EquationInputArea::AddEquationButton_Click(Object ^ sender, RoutedEventArgs
void EquationInputArea::AddNewEquation()
{
auto eq = ref new EquationViewModel();
auto eq = ref new EquationViewModel(ref new Equation());
m_lastLineColorIndex = (m_lastLineColorIndex + 1) % AvailableColors->Size;
@ -111,7 +111,7 @@ void EquationInputArea::EquationTextBox_KeyGraphFeaturesButtonClicked(Object ^ s
auto tb = static_cast<EquationTextBox ^>(sender);
auto eq = static_cast<EquationViewModel ^>(tb->DataContext);
EquationVM = eq;
KeyGraphFeaturesVisibilityChanged(this, ref new RoutedEventArgs());
KeyGraphFeaturesRequested(EquationVM, ref new RoutedEventArgs());
}
void EquationInputArea::EquationTextBox_EquationButtonClicked(Object ^ sender, RoutedEventArgs ^ e)

View File

@ -23,7 +23,7 @@ namespace CalculatorApp
OBSERVABLE_PROPERTY_RW_ALWAYS_NOTIFY(ViewModel::EquationViewModel ^, EquationVM);
OBSERVABLE_PROPERTY_RW(Windows::Foundation::Collections::IObservableVector<Windows::UI::Xaml::Media::SolidColorBrush ^> ^, AvailableColors);
event Windows::UI::Xaml::RoutedEventHandler ^ KeyGraphFeaturesVisibilityChanged;
event Windows::UI::Xaml::RoutedEventHandler ^ KeyGraphFeaturesRequested;
private:
void OnPropertyChanged(Platform::String^ propertyName);

View File

@ -182,7 +182,6 @@
Grid.Column="0">
<Grid Grid.Row="0" Margin="0,4,0,0">
<graphControl:Grapher Name="GraphingControl"
EquationsSource="{x:Bind ViewModel.Equations, Mode=OneWay}"
ForceProportionalAxes="True"
LosingFocus="GraphingControl_LosingFocus"
LostFocus="GraphingControl_LostFocus"
@ -191,30 +190,6 @@
<graphControl:Grapher.Background>
<SolidColorBrush Color="White"/>
</graphControl:Grapher.Background>
<graphControl:Grapher.EquationTemplate>
<DataTemplate x:DataType="vm:EquationViewModel">
<graphControl:Equation AnalysisError="{x:Bind AnalysisError, Mode=TwoWay}"
Domain="{x:Bind Domain, Mode=TwoWay}"
Expression="{x:Bind Expression, Mode=OneWay}"
HorizontalAsymptotes="{x:Bind HorizontalAsymptotes, Mode=TwoWay}"
InflectionPoints="{x:Bind InflectionPoints, Mode=TwoWay}"
IsAnalysisUpdated="{x:Bind IsAnalysisUpdated, Mode=TwoWay}"
LineColor="{x:Bind LineColor, Mode=OneWay}"
Maxima="{x:Bind Maxima, Mode=TwoWay}"
Minima="{x:Bind Minima, Mode=TwoWay}"
Monotonicity="{x:Bind Monotonicity, Mode=TwoWay}"
ObliqueAsymptotes="{x:Bind ObliqueAsymptotes, Mode=TwoWay}"
Parity="{x:Bind Parity, Mode=TwoWay}"
PeriodicityDirection="{x:Bind PeriodicityDirection, Mode=TwoWay}"
PeriodicityExpression="{x:Bind PeriodicityExpression, Mode=TwoWay}"
Range="{x:Bind Range, Mode=TwoWay}"
TooComplexFeatures="{x:Bind TooComplexFeatures, Mode=TwoWay}"
VerticalAsymptotes="{x:Bind VerticalAsymptotes, Mode=TwoWay}"
XIntercept="{x:Bind XIntercept, Mode=TwoWay}"
YIntercept="{x:Bind YIntercept, Mode=TwoWay}"/>
</DataTemplate>
</graphControl:Grapher.EquationTemplate>
</graphControl:Grapher>
<StackPanel Grid.Row="0"
@ -525,7 +500,7 @@
Margin="0,4,0,0"
Visibility="{x:Bind IsKeyGraphFeaturesVisible, Converter={StaticResource BooleanToVisibilityNegationConverter}, Mode=OneWay}"
Equations="{x:Bind ViewModel.Equations}"
KeyGraphFeaturesVisibilityChanged="OnEquationKeyGraphFeaturesVisibilityChanged"/>
KeyGraphFeaturesRequested="OnEquationKeyGraphFeaturesRequested"/>
<Grid x:Name="ButtonContainerGrid"
Grid.Row="1"

View File

@ -77,9 +77,43 @@ void GraphingCalculator::OnShowTracePopupChanged(bool newValue)
void GraphingCalculator::GraphingCalculator_DataContextChanged(FrameworkElement ^ sender, DataContextChangedEventArgs ^ args)
{
if (ViewModel != nullptr)
{
if (m_vectorChangedToken.Value != 0)
{
ViewModel->Equations->VectorChanged -= m_vectorChangedToken;
m_vectorChangedToken.Value = 0;
}
if (m_variableUpdatedToken.Value != 0)
{
ViewModel->VariableUpdated -= m_variableUpdatedToken;
m_variableUpdatedToken.Value = 0;
}
}
ViewModel = dynamic_cast<GraphingCalculatorViewModel ^>(args->NewValue);
ViewModel->VariableUpdated += ref new EventHandler<VariableChangedEventArgs>(this, &CalculatorApp::GraphingCalculator::OnVariableChanged);
m_vectorChangedToken = ViewModel->Equations->VectorChanged +=
ref new VectorChangedEventHandler<EquationViewModel ^>(this, &GraphingCalculator::OnEquationsVectorChanged);
m_variableUpdatedToken = ViewModel->VariableUpdated +=
ref new EventHandler<VariableChangedEventArgs>(this, &CalculatorApp::GraphingCalculator::OnVariableChanged);
}
void GraphingCalculator::OnEquationsVectorChanged(IObservableVector<EquationViewModel ^> ^ sender, IVectorChangedEventArgs ^ event)
{
if (event->CollectionChange != ::CollectionChange::ItemChanged)
{
GraphingControl->Equations->Clear();
for (auto equationViewModel : ViewModel->Equations)
{
GraphingControl->Equations->Append(equationViewModel->GraphEquation);
}
GraphingControl->PlotGraph();
}
}
void GraphingCalculator::OnTracePointChanged(Windows::Foundation::Point newPoint)
@ -331,8 +365,11 @@ void GraphingCalculator::GraphingControl_LosingFocus(UIElement ^ sender, LosingF
}
}
void GraphingCalculator::OnEquationKeyGraphFeaturesVisibilityChanged(Object ^ sender, RoutedEventArgs ^ e)
void GraphingCalculator::OnEquationKeyGraphFeaturesRequested(Object ^ sender, RoutedEventArgs ^ e)
{
auto equationViewModel = static_cast<EquationViewModel ^>(sender);
GraphingControl->AnalyzeEquation(equationViewModel->GraphEquation);
equationViewModel->PopulateKeyGraphFeatures();
IsKeyGraphFeaturesVisible = true;
}

View File

@ -34,6 +34,9 @@ namespace CalculatorApp
void GraphingCalculator_DataContextChanged(Windows::UI::Xaml::FrameworkElement^ sender, Windows::UI::Xaml::DataContextChangedEventArgs^ args);
void OnVariableChanged(Platform::Object^ sender, CalculatorApp::ViewModel::VariableChangedEventArgs args);
void OnEquationsVectorChanged(
Windows::Foundation::Collections::IObservableVector<CalculatorApp::ViewModel::EquationViewModel ^> ^ sender,
Windows::Foundation::Collections::IVectorChangedEventArgs ^ event);
void TextBoxLosingFocus(Windows::UI::Xaml::Controls::TextBox^ textbox, Windows::UI::Xaml::Input::LosingFocusEventArgs^ args);
void TextBoxKeyDown(Windows::UI::Xaml::Controls::TextBox^ textbox, Windows::UI::Xaml::Input::KeyRoutedEventArgs^ e);
@ -55,6 +58,8 @@ namespace CalculatorApp
private:
Windows::Foundation::EventRegistrationToken m_dataRequestedToken;
Windows::Foundation::EventRegistrationToken m_vectorChangedToken;
Windows::Foundation::EventRegistrationToken m_variableUpdatedToken;
void OnDataRequested(Windows::ApplicationModel::DataTransfer::DataTransferManager^ sender, Windows::ApplicationModel::DataTransfer::DataRequestedEventArgs^ e);
void TextBoxGotFocus(Windows::UI::Xaml::Controls::TextBox^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
@ -62,7 +67,7 @@ namespace CalculatorApp
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 OnEquationKeyGraphFeaturesVisibilityChanged(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnEquationKeyGraphFeaturesRequested(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
void OnKeyGraphFeaturesClosed(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
bool ActiveTracingOn;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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