fixes EETypeLoadException issue: export class DelegateCommand (#18)

* fixes EETypeLoadException issue: export class DelegateCommand

* weak-reference in C++/CX

* WeakRef in C# codebase

* UTF-8-BOM

* spaces in macro

* resolve some comments from the offline review

* format

* rename file
This commit is contained in:
Tian L 2021-04-22 14:07:24 +08:00 committed by GitHub
commit b53600bfc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 78 additions and 73 deletions

View file

@ -7,18 +7,14 @@ namespace CalculatorApp
{ {
namespace Common namespace Common
{ {
template <typename TTarget> public delegate void DelegateCommandHandler(Platform::Object ^ parameter);
ref class DelegateCommand : public Windows::UI::Xaml::Input::ICommand
{
internal :
typedef void (TTarget::*CommandHandlerFunc)(Platform::Object ^); public ref class DelegateCommand sealed : public Windows::UI::Xaml::Input::ICommand
DelegateCommand(TTarget ^ target, CommandHandlerFunc func)
: m_weakTarget(target)
, m_function(func)
{ {
} public:
DelegateCommand(DelegateCommandHandler ^ handler)
: m_handler(handler)
{}
private: private:
// Explicit, and private, implementation of ICommand, this way of programming makes it so // Explicit, and private, implementation of ICommand, this way of programming makes it so
@ -27,11 +23,7 @@ namespace CalculatorApp
// code in the app calling Execute. // code in the app calling Execute.
virtual void ExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute virtual void ExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::Execute
{ {
TTarget ^ target = m_weakTarget.Resolve<TTarget>(); m_handler->Invoke(parameter);
if (target)
{
(target->*m_function)(parameter);
}
} }
virtual bool CanExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::CanExecute virtual bool CanExecuteImpl(Platform::Object ^ parameter) sealed = Windows::UI::Xaml::Input::ICommand::CanExecute
@ -52,17 +44,25 @@ namespace CalculatorApp
} }
private: private:
DelegateCommandHandler ^ m_handler;
event Windows::Foundation::EventHandler<Platform::Object ^> ^ m_canExecuteChanged; event Windows::Foundation::EventHandler<Platform::Object ^> ^ m_canExecuteChanged;
CommandHandlerFunc m_function;
Platform::WeakReference m_weakTarget;
}; };
template <typename TTarget, typename TFuncPtr> template <typename TTarget, typename TFuncPtr>
DelegateCommand<TTarget> ^ MakeDelegate(TTarget ^ target, TFuncPtr&& function) { DelegateCommandHandler ^ MakeDelegateCommandHandler(TTarget ^ target, TFuncPtr&& function)
return ref new DelegateCommand<TTarget>(target, std::forward<TFuncPtr>(function)); {
Platform::WeakReference weakTarget(target);
return ref new DelegateCommandHandler([weakTarget, function=std::forward<TFuncPtr>(function)](Platform::Object ^ param)
{
TTarget ^ thatTarget = weakTarget.Resolve<TTarget>();
if (nullptr != thatTarget)
{
(thatTarget->*function)(param);
}
}
);
}
}
} }
}
}

View file

@ -168,11 +168,22 @@ public:
// The variable member generated by this macro should not be used in the class code, use the // The variable member generated by this macro should not be used in the class code, use the
// property getter instead. // property getter instead.
#define COMMAND_FOR_METHOD(p, m) \ #define COMMAND_FOR_METHOD(p, m) \
property Windows::UI::Xaml::Input::ICommand^ p {\ property Windows::UI::Xaml::Input::ICommand ^ p \
Windows::UI::Xaml::Input::ICommand^ get() {\ { \
if (!donotuse_##p) {\ Windows::UI::Xaml::Input::ICommand ^ get() \
donotuse_##p = CalculatorApp::Common::MakeDelegate(this, &m);\ { \
} return donotuse_##p; }} private: Windows::UI::Xaml::Input::ICommand^ donotuse_##p; \ if (!donotuse_##p) \
{ \
donotuse_##p = ref new CalculatorApp::Common::DelegateCommand( \
CalculatorApp::Common::MakeDelegateCommandHandler(this, &m) \
); \
} \
return donotuse_##p; \
} \
} \
\
private: \
Windows::UI::Xaml::Input::ICommand ^ donotuse_##p; \
\ \
public: public:

View file

@ -151,11 +151,11 @@
<Compile Include="Converters\ItemSizeToVisibilityConverter.cs" /> <Compile Include="Converters\ItemSizeToVisibilityConverter.cs" />
<Compile Include="Converters\RadixToStringConverter.cs" /> <Compile Include="Converters\RadixToStringConverter.cs" />
<Compile Include="Converters\VisibilityNegationConverter.cs" /> <Compile Include="Converters\VisibilityNegationConverter.cs" />
<Compile Include="DelegateCommand.cs" />
<Compile Include="EquationStylePanelControl.xaml.cs"> <Compile Include="EquationStylePanelControl.xaml.cs">
<DependentUpon>EquationStylePanelControl.xaml</DependentUpon> <DependentUpon>EquationStylePanelControl.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="KeyGraphFeaturesTemplateSelector.cs" /> <Compile Include="KeyGraphFeaturesTemplateSelector.cs" />
<Compile Include="Utils\DelegateCommandUtils.cs" />
<Compile Include="Views\Calculator.xaml.cs"> <Compile Include="Views\Calculator.xaml.cs">
<DependentUpon>Calculator.xaml</DependentUpon> <DependentUpon>Calculator.xaml</DependentUpon>
</Compile> </Compile>

View file

@ -1,35 +0,0 @@
using System;
namespace CalculatorApp.Common
{
internal class DelegateCommand<TTarget> : System.Windows.Input.ICommand
{
public delegate void CommandHandlerFunc(object obj);
public DelegateCommand(TTarget target, CommandHandlerFunc func)
{
m_weakTarget = new WeakReference(target);
m_function = func;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
object target = m_weakTarget.Target;
if (target != null && target is TTarget)
{
m_function(parameter);
}
}
private CommandHandlerFunc m_function;
private WeakReference m_weakTarget;
}
}

View file

@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using System;
using CalculatorApp.Common;
namespace CalculatorApp.Utils
{
static class DelegateCommandUtils
{
public static DelegateCommand MakeDelegateCommand<TTarget>(TTarget target, DelegateCommandHandler handler)
where TTarget : class
{
WeakReference weakTarget = new WeakReference(target);
return new DelegateCommand(param =>
{
TTarget thatTarget = weakTarget.Target as TTarget;
if(null != thatTarget)
{
handler.Invoke(param);
}
});
}
}
}

View file

@ -9,6 +9,7 @@ using CalculatorApp;
using CalculatorApp.Common; using CalculatorApp.Common;
using CalculatorApp.Converters; using CalculatorApp.Converters;
using CalculatorApp.Controls; using CalculatorApp.Controls;
using CalculatorApp.Utils;
using CalculatorApp.ViewModel; using CalculatorApp.ViewModel;
using Windows.Foundation; using Windows.Foundation;
@ -140,7 +141,7 @@ namespace CalculatorApp
{ {
if (donotuse_HistoryButtonPressed == null) if (donotuse_HistoryButtonPressed == null)
{ {
donotuse_HistoryButtonPressed = new DelegateCommand<Calculator>(this, ToggleHistoryFlyout); donotuse_HistoryButtonPressed = DelegateCommandUtils.MakeDelegateCommand(this, ToggleHistoryFlyout);
} }
return donotuse_HistoryButtonPressed; return donotuse_HistoryButtonPressed;
} }

View file

@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Diagnostics; using System.Diagnostics;
using CalculatorApp; using CalculatorApp;
using CalculatorApp.Utils;
using CalculatorApp.ViewModel; using CalculatorApp.ViewModel;
using Windows.Foundation; using Windows.Foundation;
@ -47,7 +48,7 @@ namespace CalculatorApp
{ {
if (donotuse_ButtonPressed == null) if (donotuse_ButtonPressed == null)
{ {
donotuse_ButtonPressed = new CalculatorApp.Common.DelegateCommand<CalculatorScientificAngleButtons>(this, OnAngleButtonPressed); donotuse_ButtonPressed = DelegateCommandUtils.MakeDelegateCommand(this, OnAngleButtonPressed);
} }
return donotuse_ButtonPressed; return donotuse_ButtonPressed;
} }

View file

@ -9,6 +9,7 @@ using CalculatorApp;
using CalculatorApp.Common; using CalculatorApp.Common;
using CalculatorApp.Common.Automation; using CalculatorApp.Common.Automation;
using CalculatorApp.Controls; using CalculatorApp.Controls;
using CalculatorApp.Utils;
using CalculatorApp.ViewModel; using CalculatorApp.ViewModel;
//using CalcManager.NumberFormattingUtils; //using CalcManager.NumberFormattingUtils;
using GraphControl; using GraphControl;
@ -114,7 +115,7 @@ namespace CalculatorApp
{ {
if (donotuse_ZoomOutButtonPressed == null) if (donotuse_ZoomOutButtonPressed == null)
{ {
donotuse_ZoomOutButtonPressed = new DelegateCommand<GraphingCalculator>(this, OnZoomOutCommand); donotuse_ZoomOutButtonPressed = DelegateCommandUtils.MakeDelegateCommand(this, OnZoomOutCommand);
} }
return donotuse_ZoomOutButtonPressed; return donotuse_ZoomOutButtonPressed;
} }
@ -127,7 +128,7 @@ namespace CalculatorApp
{ {
if (donotuse_ZoomInButtonPressed == null) if (donotuse_ZoomInButtonPressed == null)
{ {
donotuse_ZoomInButtonPressed = new DelegateCommand<GraphingCalculator>(this, OnZoomInCommand); donotuse_ZoomInButtonPressed = DelegateCommandUtils.MakeDelegateCommand(this, OnZoomInCommand);
} }
return donotuse_ZoomInButtonPressed; return donotuse_ZoomInButtonPressed;
} }

View file

@ -2,6 +2,7 @@
using System.Windows.Input; using System.Windows.Input;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Controls;
using CalculatorApp.Utils;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236 // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
@ -16,8 +17,7 @@ namespace CalculatorApp
{ {
if (donotuse_BitLengthButtonPressed == null) if (donotuse_BitLengthButtonPressed == null)
{ {
donotuse_BitLengthButtonPressed = donotuse_BitLengthButtonPressed = DelegateCommandUtils.MakeDelegateCommand(this, OnBitLengthButtonPressed);
new Common.DelegateCommand<CalculatorProgrammerDisplayPanel>(this, OnBitLengthButtonPressed);
} }
return donotuse_BitLengthButtonPressed; return donotuse_BitLengthButtonPressed;
} }