DbContext not getting inteliisense for SaveChanges() - oracle

I am using Entity Framework 6.0.2 and Oracle 11g.
I am trying to Add,Update and Delete objects using entity framework.
I am not getting intellisense for SaveChanges(),Remove(),Add() methods.
What references are required to get these.
I have added the following in packages.config.
here is my package.Config.
<packages>
<package id="EntityFramework" version="6.0.2" targetFramework="net45" />
<package id="odp.net.x64" version="112.3.20" targetFramework="net45" />
<package id="Oracle.DataAccess.x86" version="2.112.1.0" targetFramework="net45" />
<package id="Oracle.ManagedDataAccess" version="12.1.021" targetFramework="net45" />
<package id="Oracle.ManagedDataAccess.EntityFramework" version="12.1.021" targetFramework="net45" />
</packages>
Here is my DbContext.
public class OLADBContext:DbContext,IOLADBContext
{
protected static string m_connectionString = "";
public static OLADBContext Create()
{
ConnectionStringSettings dbSettings = ConfigurationManager.ConnectionStrings["OracleDbContext"];
if (dbSettings != null)
{
m_connectionString = dbSettings.ConnectionString;
}
return new OLADBContext(m_connectionString);
}
public OLADBContext(string connectionString)
: base(connectionString)
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("HRMS2");
modelBuilder.Configurations.Add(new EmployeeMapper());
modelBuilder.Configurations.Add(new EmpAuthMapper());
modelBuilder.Configurations.Add(new SpecialPrivilegesMapper());
modelBuilder.Configurations.Add(new ProbationDetailsMapper());
base.OnModelCreating(modelBuilder);
}
public DbSet<Employee> Employes { get; set; }
public DbSet<EmpAuthentication> Authentication { get; set; }
public DbSet<SpecialPrivileges> SpecialPrivilege { get; set; }
public DbSet<ProbationDetails> ProbationDetails { get; set; }
}
here is my code:
public void CheckEmployeeExists(string EmpId)
{
var userType="N";
var authenticationDetails = _olaDbContext.Authentication.Where(a => a.IsEnabled == "Y" && a.EmployeeId == EmpId).FirstOrDefault();
if (authenticationDetails == null)
{
var emp = _olaDbContext.Employes.Where(e=>e.EmployeeId==EmpId).FirstOrDefault();
if (emp != null)
{
if (emp.IsManager == "Y")
userType = "T";
else if (emp.Designation.ToUpper().Contains("HR EXEC") || emp.Designation_Id == 447)
{
userType = "H";
}
else if (emp.Designation.Contains("Time Office"))
{
userType = "A";
}
var probationDetails = _olaDbContext.ProbationDetails.Where(p => p.EmployeeId == EmpId);
ProbationDetails oprob = new ProbationDetails();
oprob.EmployeeId = "16785";
oprob.ProbatoionPeriod = 3;
_olaDbContext.ProbationDetails.Add(oprob);
}
}
}
Please let me know how can i acheive?

I got it fixed.
I am doing the mistake instead of referencing the OLADbConext directly I am referencing the IOLADbContext in my class
public class OLADBContext:DbContext,IOLADBContext
{
}
i have commented the code referencing the interface and used directly the class
public class OLADataProvider:IOLADataProvider
{
// private IOLADBContext _olaDbContext;
private OLADBContext _olaDbContext;
public OLADataProvider(OLADBContext olaDbContext)
{
if (olaDbContext == null)
throw new ArgumentNullException("olaDbContext is Null");
//_olaDbContext = olaDbContext;
_olaDbContext = olaDbContext;
}

Related

Display Dates from a List in a CalendarView Xamarin

I have a CalendarioView from this Xamarin.Plugin.Calendar nuget package.
I've been following this tutorial, and I want to have the same result. Instead of assigning the EventCollection list manually, as in the example, I have my List.
How to fill it in the EventCollection? I've searched and didn't find anything that worked.
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:c ="clr-namespace:Minha_Carteira_Hospitalar.Controls"
x:Class="Minha_Carteira_Hospitalar.Views.PlanoReceita"
xmlns:controls="clr-namespace:Xamarin.Plugin.Calendar.Controls;assembly=Xamarin.Plugin.Calendar">
<controls:Calendar
Events="{Binding Events}"
>
<controls:Calendar.EventTemplate>
<DataTemplate>
<StackLayout Padding="15,0,0,0">
<Label
Text="{Binding Name}"
FontAttributes="Bold"
FontSize="Medium" />
</StackLayout>
</DataTemplate>
</controls:Calendar.EventTemplate>
</controls:Calendar>
MVVM code
public EventCollection Events;
public ObservableCollection<Plans> myPlans= new ObservableCollection<Plans>();
public ObservableCollection<Plans> MyPlans
{
get => myPlans;
set => myPlans= value;
}
public MyPlansViewModel()
{
Events = new EventCollection();
}
public ICommand LoadingMyPlans
{
get
{
return new Command(async () =>
{
try
{
List<Plans> tmp = await App.Database.GetMyPlans();
foreach(var item in tmp)
{
MyPlans.Clear();
tmp.ForEach(i => MyPlans.Add(i));
Events.Add(item.DatePlan, MyPlans);
}
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "OK");
}
});
}
}
I am not sure where you use the LoadingMyPlans for. I make a simple example about how to fill your own list into EventCollection for your reference.
The same Xaml as yours.
Model:
public class Plans
{
public DateTime dateTime { get; set; }
public List<Plan> plans { get; set; }
}
public class Plan
{
public string Name { get; set; }
public string Desc { get; set; }
}
ViewModel:
public class CalendarViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value))
{
return false;
}
storage = value;
OnPropertyChanged(propertyName);
return true;
}
public EventCollection Events { get; set; }
public ObservableCollection<Plans> plans { get; set; }
public CalendarViewModel()
{
plans = new ObservableCollection<Plans>()
{
new Plans(){ dateTime=DateTime.Now, plans=new List<Plan>() { new Plan() { Name = "Plan_A", Desc = "aaaaa" }, new Plan() { Name = "Plan_A2", Desc = "aaaaa2" } }},
new Plans(){ dateTime=DateTime.Now.AddDays(5), plans=new List<Plan>() { new Plan() { Name = "Plan_B", Desc = "bbbbb" }, new Plan() { Name = "Plan_B2", Desc = "aaaaa2" } }},
new Plans(){ dateTime=DateTime.Now.AddDays(-3), plans=new List<Plan>() { new Plan() { Name = "Plan_C", Desc = "ccccc" }}}
};
Events = new EventCollection();
foreach (var item in plans)
{
Events.Add(item.dateTime, item.plans);
}
}
}
Code behind:
public Page2()
{
InitializeComponent();
this.BindingContext = new CalendarViewModel();
}

How to Binding Result from ViewModel in Xamarin

I have 1 question here: How to get data from ViewModel in Xamarin, however I still haven't solved the problem. I created a new post with some changes.
I have:
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding Customer.Address}" />
</RefreshView>
</StackLayout>
PageOne.xaml.cs
ViewCustomerViewModel viewCustomerViewModel;
public Customer CustomerGet { get; set; }
public PageOne()
{
InitializeComponent();
BindingContext = viewCustomerViewModel = new ViewCustomerViewModel();
viewCustomerViewModel.OnAppearing();
}
Class Customer
public class Customer
{
public string Address{ get; set; }
........
}
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; }
public ObservableCollection<Customer> CustomerInfos { get; set; }
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
CustomerInfos = new ObservableCollection<Customer>();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
CustomerInfos.Clear();
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerInfos.Add(customerList);
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
And I got the result CustomerInfos.Add(customerList);
However <Label Text="{Binding Customer.Address}" /> does not get results
Please help me again clearly in the answer. Thank you.
Update
ViewCustomerViewModel
public class ViewCustomerViewModel:BaseCustomerViewModel
{
ApiServiceUserinfo apiServiceUserinfo = new ApiServiceUserinfo();
public Command LoadUserinfoCommand { get; set;}
public Customer CustomerGets { get; set;}--> update
public ViewCustomerViewModel()
{
LoadUserinfoCommand = new Command(async () => await ExecuteLoadUserinfoCommand());
//CustomerGets = new Customer();
}
public void OnAppearing()
{
IsBusy = true;
}
async Task ExecuteLoadUserinfoCommand()
{
string userget = "1";
IsBusy = true;
try
{
var customerList = await apiServiceUserinfo.GetCustomersInfo(userget);
CustomerGets = customerList;
}
catch (Exception)
{
throw;
}
finally
{
IsBusy = false;
}
}
}
PageOne.xaml
<StackLayout>
<RefreshView x:DataType="locals:ViewCustomerViewModel" Command="{Binding LoadUserinfoCommand}" IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<Label Text="{Binding CustomerGets.Address}" />
</RefreshView>
</StackLayout>
We need to call the OnPropertyChanged method to notify the change in setter method of the property .
private Customer customerGets;
public Customer CustomerGets {
get { return customerGets; }
set {
customerGets = value;
NotifyPropertyChanged(); //the method is declared in BaseCustomerViewModel
}
}
Ensure that BaseCustomerViewModel has implemented INotifyPropertyChanged , something like that
public class BaseCustomerViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

How to navigate between view models via BottomNavigationView in Xamarin MvvmCross

Let's say we have MvvmCross 6.0.1 native app with one Android Activity containing BottomNavigationView implemented as in this blog post by James Montemagno but without navigating and replacing fragments.
What I would like to do is to bind BottomNavigationView items to MvxCommands (or MvxAsyncCommands) in ViewModel in order to navigate between several ViewModels.
What kind of architecture should I apply to achieve this? Is my approach correct or am I doing something against MVVM pattern and MvvmCross possibilities?
Full working example with several additions can be found here on github.
At the moment I have (scaffolded with MvxScaffolding).
MainContainerActivity and corresponding MainContainerViewModel - here I would like to store commands to navigate between view models
MainFragment and corresponding MainViewModel - this is the first fragment/view model
SettingsFragment and corresponding SettingsViewModel - I would like to navigate to it from MainViewModel and vice versa
FavoritesFragment and corresponding FavoritesViewModel
The main activity is as follows:
using Android.App;
using Android.OS;
using Android.Views;
using PushNotifTest.Core.ViewModels.Main;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Microsoft.AppCenter.Push;
using Android.Graphics.Drawables;
using Android.Support.Design.Widget;
using MvvmCross.Binding.BindingContext;
using System;
using System.Windows.Input;
namespace PushNotifTest.Droid.Views.Main
{
[Activity(
Theme = "#style/AppTheme",
WindowSoftInputMode = SoftInput.AdjustResize | SoftInput.StateHidden)]
public class MainContainerActivity : BaseActivity<MainContainerViewModel>
{
protected override int ActivityLayoutId => Resource.Layout.activity_main_container;
BottomNavigationView bottomNavigation;
public ICommand GoToSettingsCommand { get; set; }
public ICommand GoToFavoritesCommand { get; set; }
public ICommand GoToHomeCommand { get; set; }
protected override void OnCreate(Bundle bundle)
{
base.OnCreate();
AddBottomNavigation();
}
private void AddBottomNavigation()
{
bottomNavigation = (BottomNavigationView)FindViewById(Resource.Id.bottom_navigation);
if (bottomNavigation != null)
{
bottomNavigation.NavigationItemSelected += BottomNavigation_NavigationItemSelected;
// trying to bind command to view model property
var set = this.CreateBindingSet<MainContainerActivity, MainContainerViewModel>();
set.Bind(this).For(v => v.GoToSettingsCommand).To(vm => vm.NavigateToSettingsCommand);
set.Bind(this).For(v => v.GoToHomeCommand).To(vm => vm.NavigateToHomeCommand);
set.Bind(this).For(v => v.GoToFavoritesCommand).To(vm => vm.NavigateToFavoritesCommand);
set.Apply();
}
else
{
System.Diagnostics.Debug.WriteLine("Bottom navigation menu is null");
}
}
private void BottomNavigation_NavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
{
try
{
System.Diagnostics.Debug.WriteLine($"Bottom navigation menu is selected: {e.Item.ItemId}");
if (e.Item.ItemId == Resource.Id.menu_settings)
if (GoToSettingsCommand != null && GoToSettingsCommand.CanExecute(null))
GoToSettingsCommand.Execute(null);
if (e.Item.ItemId == Resource.Id.menu_list)
if (GoToFavoritesCommand != null && GoToFavoritesCommand.CanExecute(null))
GoToFavoritesCommand.Execute(null);
if (e.Item.ItemId == Resource.Id.menu_home)
if (GoToHomeCommand != null && GoToHomeCommand.CanExecute(null))
GoToHomeCommand.Execute(null);
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine($"Exception: {exception.Message}");
Crashes.TrackError(exception);
}
}
}
}
The bottom navigation elements are:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_home"
android:enabled="true"
android:icon="#drawable/ic_history"
android:title="#string/tab1_title"
app:showAsAction="ifRoom" />
<item
android:id="#+id/menu_list"
android:enabled="true"
android:icon="#drawable/ic_list"
android:title="#string/tab2_title"
app:showAsAction="ifRoom" />
<item
android:id="#+id/menu_settings"
android:enabled="true"
android:icon="#drawable/ic_settings"
android:title="#string/tab3_title"
app:showAsAction="ifRoom" />
</menu>
And the commands in view model are just:
public IMvxAsyncCommand NavigateToSettingsCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<SettingsViewModel>());
public IMvxAsyncCommand NavigateToFavoritesCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<FavoritesViewModel>());
public IMvxAsyncCommand NavigateToHomeCommand => new MvxAsyncCommand(async () => await _navigationService.Navigate<MainViewModel>());
Instead of using Fluent Binding, you could create a targeted binding for the BottomNavigationView and handle the navigation in your MainViewModel. Use Swiss binding in your XML.
TargetBinding Class:
public class MvxBottomNavigationItemChangedBinding : MvxAndroidTargetBinding
{
readonly BottomNavigationView _bottomNav;
IMvxCommand _command;
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
public override Type TargetType => typeof(MvxCommand);
public MvxBottomNavigationItemChangedBinding(BottomNavigationView bottomNav) : base(bottomNav)
{
_bottomNav = bottomNav;
_bottomNav.NavigationItemSelected += OnNavigationItemSelected;
}
public override void SetValue(object value)
{
_command = (IMvxCommand)value;
}
protected override void SetValueImpl(object target, object value)
{
}
void OnNavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
{
if (_command != null)
_command.Execute(e.Item.TitleCondensedFormatted.ToString());
}
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
_bottomNav.NavigationItemSelected -= OnNavigationItemSelected;
base.Dispose(isDisposing);
}
}
Setup.cs :
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
MvxAppCompatSetupHelper.FillTargetFactories(registry);
base.FillTargetFactories(registry);
registry.RegisterCustomBindingFactory<BottomNavigationView>("BottomNavigationSelectedBindingKey",
view => new MvxBottomNavigationItemChangedBinding(view));
}
BottomNavigationView XML :
Note the target binding key that we added in Setup.cs is used when binding.
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/navigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/white"
app:labelVisibilityMode="labeled"
app:menu="#menu/bottom_nav_menu"
app:elevation="10dp"
local:MvxBind="BottomNavigationSelectedBindingKey BottomNavigationItemSelectedCommand"/>
MainViewModel :
public class MainViewModel : BaseViewModel
{
public IMvxCommand<string> BottomNavigationItemSelectedCommand { get; private set; }
List<TabViewModel> _tabs;
public List<TabViewModel> Tabs
{
get => _tabs;
set => SetProperty(ref _tabs, value);
}
public MainViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
//these are for android - start
BottomNavigationItemSelectedCommand = new MvxCommand<string>(BottomNavigationItemSelected);
var tabs = new List<TabViewModel>
{
Mvx.IoCProvider.IoCConstruct<FirstViewModel>(),
Mvx.IoCProvider.IoCConstruct<SecondViewModel>(),
Mvx.IoCProvider.IoCConstruct<ThirdViewModel>()
};
Tabs = tabs;
//end
}
// Android-only, not used on iOS
private void BottomNavigationItemSelected(string tabId)
{
if (tabId == null)
{
return;
}
foreach (var item in Tabs)
{
if (tabId == item.TabId)
{
_navigationService.Navigate(item);
break;
}
}
}
}
TabViewModel :
public class TabViewModel : BaseViewModel
{
public string TabName { get; protected set; }
public string TabId { get; protected set; }
public TabViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
}
}
BottomNavigation Elements:
Add "android:titleCondensed", which will be used as the Id.
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="#+id/menu_home"
android:enabled="true"
android:icon="#drawable/ic_history"
android:title="#string/tab1_title"
android:titleCondensed ="tab_first"
app:showAsAction="ifRoom" />
<item
android:id="#+id/menu_list"
android:enabled="true"
android:icon="#drawable/ic_list"
android:title="#string/tab2_title"
android:titleCondensed ="tab_second"
app:showAsAction="ifRoom" />
<item
android:id="#+id/menu_settings"
android:enabled="true"
android:icon="#drawable/ic_settings"
android:title="#string/tab3_title"
android:titleCondensed ="tab_third"
app:showAsAction="ifRoom" />
</menu>
ViewModel Examples:
public class FirstViewModel : TabViewModel
{
public FirstViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
TabId = "tab_first";
}
}
public class SecondViewModel : TabViewModel
{
public SecondViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
TabId = "tab_second";
}
}
Hope this helps someone else who comes into this later on ! :)

CustomFragment in MVVMCross

I have used the following template in my Android application which has navigation drawer has a list of options such as Settings.
https://github.com/MvvmCross/MvvmCross-Samples/tree/master/XPlatformMenus
Source code could be downloaded from the following url
https://github.com/MvvmCross/MvvmCross-Samples
I wonder how could I able to make Settings page as a Dialog or CustomFragment which will look like similar to following image.
One approach that you could make use of is to create a custom implementation of Dialog. Following the XPlatformMenus sample you linked to, you could implement something as follows:
Generic Custom Dialog
This class inherits android Dialog control, and can be used with any XML/AXML layout you want. You could tightly couple it to a particular ViewModel/Layout or you can make it handle a generic ViewModel type. Here is an example of the generic type:
public class CustomDialog : Dialog, IMvxBindingContextOwner
{
public CustomDialog(Context context, int layout, IMvxViewModel viewModel)
: this(context, Resource.Style.CustomDialog)
{
this.BindingContext = new MvxAndroidBindingContext(context, (context as IMvxLayoutInflaterHolder));
ViewModel = viewModel;
Init(layout);
}
public CustomDialog(Context context, int themeResId)
: base(context, themeResId)
{
}
protected CustomDialog(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}
protected CustomDialog(Context context, bool cancelable, IDialogInterfaceOnCancelListener cancelListener)
: base(context, cancelable, cancelListener)
{
}
protected CustomDialog(Context context, bool cancelable, EventHandler cancelHandler)
: base(context, cancelable, cancelHandler)
{
}
private void Init(int layout)
{
SetContentView(layout);
}
public override void SetContentView(int layoutResID)
{
var view = this.BindingInflate(layoutResID, null);
base.SetContentView(view);
}
public IMvxBindingContext BindingContext { get; set; }
public object DataContext
{
get { return this.BindingContext.DataContext; }
set { this.BindingContext.DataContext = value; }
}
public IMvxViewModel ViewModel
{
get { return this.DataContext as IMvxViewModel; }
set { this.DataContext = value; }
}
}
XML layout for modal:
<?xml version="1.0" encoding="utf-8" ?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary">
<Button
android:id="#+id/btn_option"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Show"
local:MvxBind="Click ShowSettingsCommand"/>
<Button
android:id="#+id/btn_close"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#id/btn_option"
android:text="CLOSE"
local:MvxBind="Click ShowCloseCommand"/>
</RelativeLayout>
CustomDialog style:
<resources>
<style name="CustomDialog">
<item name="android:windowIsFloating">true</item>
<item name="android:windowNoTitle">true</item>
</style>
</resources>
Custom Presenter
Create a custom presenter to handle the navigation to show/hide the dialog:
public class CustomPresenter : MvxFragmentsPresenter
{
protected IMvxViewModelLoader MvxViewModelLoader => Mvx.Resolve<IMvxViewModelLoader>();
CustomDialog _modal;
public CustomPresenter(IEnumerable<Assembly> AndroidViewAssemblies) : base(AndroidViewAssemblies)
{
}
protected override void ShowActivity(MvxViewModelRequest request, MvxViewModelRequest fragmentRequest = null)
{
if (!Intercept(request))
base.ShowActivity(request, fragmentRequest);
}
protected override void ShowFragment(MvxViewModelRequest request)
{
if (!Intercept(request))
base.ShowFragment(request);
}
private bool Intercept(MvxViewModelRequest request)
{
if (request.ViewModelType == typeof(ThirdViewModel))
{
var activity = Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;
var viewModel = MvxViewModelLoader.LoadViewModel(request, null) as ThirdViewModel;
_modal = new CustomDialog(activity, Resource.Layout.modal_popup, viewModel);
_modal.Show();
return true;
}
if (_modal != null)
{
_modal.Dismiss();
_modal = null;
}
return false;
}
}
Register your custom presenter in the setup class:
protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
var mvxFragmentsPresenter = new CustomPresenter(AndroidViewAssemblies);
Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxFragmentsPresenter);
return mvxFragmentsPresenter;
}
ViewModel
public class ThirdViewModel : BaseViewModel
{
private MvxCommand _showSettingsCommand;
public MvxCommand ShowSettingsCommand =>
_showSettingsCommand ?? (_showSettingsCommand = new MvxCommand(() => ShowViewModel<HomeViewModel>()));
private MvxCommand _showCloseCommand;
public MvxCommand ShowCloseCommand =>
_showCloseCommand ?? (_showCloseCommand = new MvxCommand(() => ShowViewModel<SettingsViewModel>()));
}

Obfuscar SkipType configuration element is not working for enums

The Obfuscar SkipType configuration element seems to be not working for enums. This is my fairly minimal configuration file.
<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0"
sku=".NETFramework,Version=v4.0,Profile=Client"/>
</startup>
<Obfuscator>
<Var name="InPath"
value="\users\user\docs\vs2013\projects\wpfapp\wpfapp\bin\debug" />
<Var name="OutPath"
value="\users\user\docs\vs2013\projects\wpfapp\wpfapp\bin\debug" />
<Module file="$(InPath)\wpfapp.exe" />
<Var name="KeepPublicApi" value="true" />
<Var name="HidePrivateApi" value="true" />
<SkipType name="WpfApp.Category" skipFields="true" skipProperties="true" />
</Obfuscator>
</configuration>
The map output file shows that the skipping did not work and the enum type Category was renamed.
Renamed Types:
[WpfApp]WpfApp.Category -> [WpfApp]A.a
{
WpfApp.Category [WpfApp]WpfApp.Category WpfApp.Category::Low -> A
WpfApp.Category [WpfApp]WpfApp.Category WpfApp.Category::High -> a
System.Int32 [WpfApp]System.Int32 WpfApp.Category::value__ skipped: special name
}
Edit: The element <SkipType name="WpfApp.Category" /> causes the same problem.
Edit: The element <SkipType name="WpfApp.Category" skipFields="true" /> causes the same problem.
Edit: The element <SkipField type="WpfApp.Category" name="*" /> causes the same problem.
Edit: This pair
<SkipField type="WpfApp.Category" name="Low" />
<SkipField type="WpfApp.Category" name="High" /> causes the same problem.
The source:
namespace WpfApp
{
public enum Category { Low, High }
//[System.Reflection.Obfuscation]
public partial class MainWindow : Window
{
private ViewModel ViewModel;
public MainWindow()
{
InitializeComponent();
this.DataContext = this.ViewModel = new ViewModel();
}
private void MyButtonClick(object sender, RoutedEventArgs e)
{
this.ViewModel.Process(MyTextBox.Text);
}
}
internal class ViewModel : WpfNotifier
{
private const float DefaultKilograms = 80.0f;
private string _kilograms;
public string Kilograms // WPF binds here
{
get { return this._kilograms; }
set { this._kilograms = value; NotifyPropertyChanged(); }
}
private string _resultText;
public string ResultText // WPF binds here
{
get { return this._resultText; }
set { this._resultText = value; NotifyPropertyChanged(); }
}
internal void Process(string input)
{
float kilograms;
if (Single.TryParse(input, out kilograms))
{
Category c = (kilograms > 100.0f) ? Category.High : Category.Low;
this.ResultText = c.ToString();
}
else
{
this.Kilograms = ViewModel.DefaultKilograms.ToString();
}
}
}
public class WpfNotifier : INotifyPropertyChanged
{
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged; // public for interface
internal void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
else
; // it is harmless to fail to notify before the window has been loaded and rendered
}
}
}
Is this a bug or is my usage wrong?
Your usage is wrong. If you check the documentation you will see that <SkipType> tags must be put into <Module> tags. Otherwise, Obfuscar has no idea in which module/assembly this skip rule takes effect. So you should try
<Module file="$(InPath)\wpfapp.exe">
<SkipType name="WpfApp.Category" skipFields="true" skipProperties="true" />
</Module>

Resources