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
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();
}
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));
}
}
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 ! :)
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>()));
}
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>