Im using the MVVMCross 4.4.0 and my FirstView is a List View like WhatsApp. When I click an item, my SecondView is a common view with just a field to update a property and change my FirstView, but this is not happen.
My First View Code
public sealed partial class MyOrdersView : MvxViewController
{
UITableView tableView;
public MyOrdersView() : base("MyOrdersView", null)
{
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
tableView = new UITableView
{
Frame = new CoreGraphics.CGRect(0, 0, View.Bounds.Width, View.Bounds.Height),
CellLayoutMarginsFollowReadableWidth = true,
};
Add(tableView);
var tableSource = new MvxSimpleTableViewSource(tableView, OrderCell.Key, OrderCell.Key);
tableView.Source = tableSource;
var set = this.CreateBindingSet<MyOrdersView, Core.ViewModels.MyOrdersViewModel>();
set.Bind(tableSource).To(vm => vm.Tasks);
set.Bind(tableSource).For(s => s.SelectionChangedCommand).To(vm => vm.ItemSelectedCommand);
set.Apply();
tableView.ReloadData();
Title = "Meus Pedidos";
AppDelegate app = UIApplication.SharedApplication.Delegate as AppDelegate;
NavigationItem.SetLeftBarButtonItem(
new UIBarButtonItem(UIImage.FromBundle("threelines")
, UIBarButtonItemStyle.Plain
, (sender, args) => app.SidebarController.ToggleMenu()), true);
}
}
And ViewModel
public class MyOrdersViewModel : BaseViewModel
{
private IOrderService orderService;
public ObservableCollection<ValOrders2TO> tasks;
private MvxCommand<ValOrders2TO> _itemSelectedCommand;
public MyOrdersViewModel(IOrderService orderService)
{
this.orderService = orderService;
tasks = orderService.getAvailableOrders();
searchMyOrders();
}
private async Task<bool> searchMyOrders()
{
orderService.clearAvailableOrders();
orderService.addAllAvailableOrders(await orderService.searchMyOrders());
return true;
}
public ObservableCollection<ValOrders2TO> Tasks
{
get { return tasks; }
set { tasks = value; RaisePropertyChanged(() => Tasks); }
}
public ICommand ItemSelectedCommand
{
get
{
_itemSelectedCommand = _itemSelectedCommand ?? new MvxCommand<ValOrders2TO>(DoSelectItem);
return _itemSelectedCommand;
}
}
private void DoSelectItem(ValOrders2TO item)
{
ShowViewModel<MyOrdersDetailModel>(new { idOrder = item.id });
}
}
My Second View Code
public sealed partial class MyOrdersDetailView : MvxViewController<MyOrdersDetailModel>
{
public MyOrdersDetailView() : base("MyOrdersDetailView", null)
{
//ViewDidLoad();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var btnBack = UIButton.FromType(UIButtonType.System);
btnBack.Frame = new CGRect(2, 35, 50, 20);
btnBack.SetTitle("Voltar", UIControlState.Normal);
Add(btnBack);
var set = this.CreateBindingSet<MyOrdersDetailView, Core.ViewModels.MyOrdersDetailModel>();
set.Bind(txtItemDes).To(vm => vm.txtItemDes);
set.Bind(btnUpdate).To(vm => vm.update);
set.Apply();
}
}
And the ViewModel
public class MyOrdersDetailModel : MvxViewModel
{
public ValOrders2TO _valItem;
public INC<string> txtItemDes = new NC<string>();
public MyOrdersDetailModel(IMessageService messageService, IOrderService orderService)
{
}
public ValOrders2TO Item
{
get { return _valItem; }
set { _valItem = value; RaisePropertyChanged(() => Item); }
}
public void Init(ValOrders2TO item)
{
Item = item;
ConfigProp();
}
void ConfigProp()
{
txtItemDes.Value = Item.itemsDes;
}
public IMvxCommand Update
{
get
{
return new MvxCommand(() => updateOrder());
}
}
private bool updateOrder()
{
Item.itemsDes = txtItemDes.Value;
return true;
}
public IMvxCommand CloseCommand
{
get { return new MvxCommand(() => Close(this)); }
}
}
This is my Bean Code
public class ValOrders2TO
{
//[JsonProperty()]
public int id { get; set; }
//[JsonProperty()]
public string itemsDes { get; set; }
}
And this is my OrderCell
public partial class OrderCell : MvxTableViewCell
{
public static readonly UINib Nib = UINib.FromName("OrderCell", NSBundle.MainBundle);
public static readonly NSString Key = new NSString("OrderCell");
private readonly MvxImageViewLoader _loader;
public OrderCell(IntPtr handle) : base(handle)
{
this.DelayBind(() =>
{
var set = this.CreateBindingSet<OrderCell, Core.ValOrders2TO>();
set.Bind(lblItemDes).To(item => item.itemsDes);
set.Apply();
});
}
public static OrderCell Create()
{
return (OrderCell)Nib.Instantiate(null, null)[0];
}
}
I know how to remove the items from my ListView like this:
orderService.deleteAvailableOrder(Item);
But I don't know how to update the items list.
Following attached my print screens
Try to implement RaisePropertyChanged for
public string itemsDes { get; set; }
Related
How can I make sure that as soon as there is a change in the text field, the save button is enabled? or clicking edit (thus creating the button) the app enables editing and thus enabling the button,
and it has already been activated in case of insertion or deletion.
this a image of
app
Here is the code:
public GerenciarGenericoViewModel()
{
InserirProdutoCommand = new RelayCommand(InserirProduto);
ExcluirProdutoCommand = new RelayCommand(ExcluirProduto, CanExcluirProduto);
InserirUnidadeCommand = new RelayCommand(InserirUnidade);
ExcluirUnidadeCommand = new RelayCommand(ExcluirUnidade, CanExcluirUnidade);
InserirEmpresaCommand = new RelayCommand(InserirEmpresa);
ExcluirEmpresaCommand = new RelayCommand(ExcluirEmpresa, CanExcluirEmpresa);
InserirOperadorCommand = new RelayCommand(InserirOperador);
ExcluirOperadorCommand = new RelayCommand(ExcluirOperador, CanExcluirOperador);
SalvarCommand = new RelayCommand(Salvar, CanSalvar);
CancelarCommand = new RelayCommand(Cancelar);
ListaProdutos = new ObservableCollection<Produto>(ProdutosAccess.GetProdutos());
ListaUnidades = new ObservableCollection<UnidadeMedida>(ProdutosAccess.GetUnidadesMedida());
ListaEmpresas = new ObservableCollection<Empresa>(ProdutosAccess.GetEmpresas());
ListaOperadores = new ObservableCollection<Operador>(ProdutosAccess.GetOperadores());
}
public RelayCommand InserirProdutoCommand { get; }
public RelayCommand ExcluirProdutoCommand { get; }
public RelayCommand InserirUnidadeCommand { get; }
public RelayCommand ExcluirUnidadeCommand { get; }
public RelayCommand InserirEmpresaCommand { get; }
public RelayCommand ExcluirEmpresaCommand { get; }
public RelayCommand InserirOperadorCommand { get; }
public RelayCommand ExcluirOperadorCommand { get; }
int check = 0;
public RelayCommand SalvarCommand { get; }
public RelayCommand CancelarCommand { get; }
public ObservableCollection<Produto> ListaProdutos { get; }
public ObservableCollection<UnidadeMedida> ListaUnidades { get; }
public ObservableCollection<Empresa> ListaEmpresas { get; }
public ObservableCollection<Operador> ListaOperadores { get; }
private Produto _produtoSelecionado;
public Produto ProdutoSelecionado
{
get => _produtoSelecionado;
set => Set(() => ProdutoSelecionado, ref _produtoSelecionado, value);
}
private UnidadeMedida _unidadeSelecionada;
public UnidadeMedida UnidadeSelecionada
{
get => _unidadeSelecionada;
set => Set(() => UnidadeSelecionada, ref _unidadeSelecionada, value);
}
private Empresa _empresaSelecionada;
public Empresa EmpresaSelecionada
{
get => _empresaSelecionada;
set => Set(() => EmpresaSelecionada, ref _empresaSelecionada, value);
}
private Operador _operadorSelecionado;
public Operador OperadorSelecionado
{
get => _operadorSelecionado;
set => Set(() => OperadorSelecionado, ref _operadorSelecionado, value);
}
public void InserirProduto()
{
ListaProdutos.Add(new Produto());
check++;
}
public void ExcluirProduto()
{
ListaProdutos.Remove(ProdutoSelecionado);
check++;
}
public bool CanExcluirProduto()
{
return ProdutoSelecionado != null;
}
public void InserirUnidade()
{
ListaUnidades.Add(new UnidadeMedida());
check++;
}
public void ExcluirUnidade()
{
ListaUnidades.Remove(UnidadeSelecionada);
check++;
}
public bool CanExcluirUnidade()
{
return UnidadeSelecionada != null;
}
public void InserirEmpresa()
{
ListaEmpresas.Add(new Empresa());
check++;
}
public void ExcluirEmpresa()
{
ListaEmpresas.Remove(EmpresaSelecionada);
check++;
}
public bool CanExcluirEmpresa()
{
return EmpresaSelecionada != null;
}
public void InserirOperador()
{
ListaOperadores.Add(new Operador());
check++;
}
public void ExcluirOperador()
{
ListaOperadores.Remove(OperadorSelecionado);
check++;
}
public bool CanExcluirOperador()
{
return OperadorSelecionado != null;
}
public void Salvar()
{
var listaProdutos = ListaProdutos.ToList();
var listaUnidades = ListaUnidades.ToList();
var listaEmpresas = ListaEmpresas.ToList();
var listaOperadores = ListaOperadores.ToList();
listaProdutos = listaProdutos.Where(x => !string.IsNullOrWhiteSpace(x.Descricao)).ToList();
listaUnidades = listaUnidades.Where(x => !string.IsNullOrWhiteSpace(x.Descricao)).ToList();
listaEmpresas = listaEmpresas.Where(x => !string.IsNullOrWhiteSpace(x.Descricao)).ToList();
listaOperadores = listaOperadores.Where(x => !string.IsNullOrWhiteSpace(x.Nome)).ToList();
ProdutosAccess.SetListProdutos(listaProdutos);
ProdutosAccess.SetListUnidades(listaUnidades);
ProdutosAccess.SetListEmpresas(listaEmpresas);
ProdutosAccess.SetListOperadores(listaOperadores);
MessageBox.Show(messageBoxText: "Dados salvos com sucesso!",
caption: "Gerenciar Dados", button: MessageBoxButton.OK,
icon: MessageBoxImage.Information);
Sair();
}
public bool CanSalvar()
{
if (check == 0)
{
return false;
}
else
{
return true;
}
}
public void Cancelar()
{
Sair();
}
public void Sair()
{
Navigator.CloseWindowByDataContext(this);
}
}
As #BradleDotNET mentioned just set the UpdateSourceTrigger inside your TextBox Text binding to PropertyChanged and it should work.
I am stuck with a problem where I am checking network connectivity in an iOS app and trying to binding a boolean hasNetworkConnection in my view controller for it's view model.
View controller UpdateContentView.cs
// This file has been autogenerated from a class added in the UI designer.
using System;
using MvvmCross.iOS.Views;
using MvvmCross.Binding.BindingContext;
using Training.Core;
namespace EdwardsTraining.IOS
{
public partial class UpdateContentView : MvxViewController
{
public UpdateContentView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
var bindingSet = this.CreateBindingSet<UpdateContentView, UpdateContentViewModel>();
bindingSet.Bind(NoConnectionView).For(x => x.Hidden).To(vm => vm.HasConnection).WithConversion("ReverseBoolean");
bindingSet.Bind(UpdateInProgressView).For(x => x.Hidden).To(vm => vm.InProgress).WithConversion("ReverseBoolean");
bindingSet.Bind(UpdateAvailableView).For(x => x.Hidden).To(vm => vm.HasContentUpdate).WithConversion("ReverseBoolean");
bindingSet.Bind(CancelButton).For(x => x.Hidden).To(vm => vm.CancelVisible).WithConversion("ReverseBoolean");
bindingSet.Bind(RetryButton).To(vm => vm.DoRetryUpdate);
bindingSet.Bind(ConfirmButton).To(vm => vm.DoUpdate);
//bindingSet.Bind(iOSNetworkConnectivitiy).For(x => x.HasNetworkConnection).To(vm => vm.NetworkConnectivitiy).TwoWay()
//.For(vm => vm.HasNetworkConnection);
bindingSet.Bind(iOSNetworkConnectivitiy).To(vm => vm.NetworkConnectivitiy).TwoWay();
bindingSet.Apply();
_iOSnetworkConnectivity = new NetworkConnectivity()
{
HasNetworkConnection = Reachability.IsNetworkAvailable()
};
}
private NetworkConnectivity _iOSnetworkConnectivity { get; set; }
public NetworkConnectivity iOSNetworkConnectivitiy {
get{return _iOSnetworkConnectivity;}
set { _iOSnetworkConnectivity = value;
}
}
}
}
I would like to check for connectivity using my iOS specific code and bind the boolean returned to a a public view model property.
View Model
using System;
using System.Threading.Tasks;
using EdwardsTraining.BusinessLayer.Interfaces.Services;
using MvvmCross.Core.ViewModels;
using MvvmCross.Platform;
namespace Training.Core
{
public class UpdateContentViewModel : BaseViewModel
{
private IApplicationContentService _applicationContentService;
private ITrainingContentService _trainingContentService;
public bool _isNetworkAvailable { get; set; }
public UpdateContentViewModel(IApplicationContentService applicationContentService, ITrainingContentService trainingContentService)
{
_applicationContentService = applicationContentService ?? Mvx.Resolve<IApplicationContentService>();
_trainingContentService = trainingContentService ?? Mvx.Resolve<ITrainingContentService>();
IntialSetup();
}
protected void IntialSetup()
{
_cancelVisible = false;
_hasContentUpdate = true;
_inProgress = false;
}
public void SetNoConnection()
{
_cancelVisible = true;
_hasContentUpdate = false;
_inProgress = false;
}
public void SetInProgress()
{
_cancelVisible = false;
HasContentUpdate = false;
InProgress = true;
}
public void SetProgessComplete()
{
InProgress = false;
Task.Run(async () => await FinishedUpdating());
}
public async Task UpdateContent()
{
if (_networkConnectivity.HasNetworkConnection)
{
SetInProgress();
await _trainingContentService.UpdateTrainingContentAsync();
await _applicationContentService.UpdateContent();
SetProgessComplete();
await FinishedUpdating();
}
return;
}
public async Task FinishedUpdating()
{
Close(this);
}
public MvxCommand DoUpdate
{
get { return new MvxCommand(async () => await UpdateContent()); }
}
public MvxCommand DoRetryUpdate
{
get { return new MvxCommand(async () => await UpdateContent()); }
}
public MvxCommand CancelUpdate
{
get { return new MvxCommand(async () => await FinishedUpdating()); }
}
private bool _hasContentUpdate;
public bool HasContentUpdate
{
get { return _hasContentUpdate; }
set
{
_hasContentUpdate = value;
RaisePropertyChanged(() => HasContentUpdate);
}
}
private bool _hasConnection;
public bool HasConnection
{
get { return _hasConnection; }
set
{
_hasConnection = value;
RaisePropertyChanged(() => HasConnection);
}
}
private bool _inProgress;
public bool InProgress
{
get { return _inProgress; }
set
{
_inProgress = value;
RaisePropertyChanged(() => InProgress);
}
}
private bool _cancelVisible;
public bool CancelVisible
{
get { return _cancelVisible; }
set
{
_cancelVisible = value;
RaisePropertyChanged(() => CancelVisible);
}
}
private NetworkConnectivity _networkConnectivity { get; set; }
public NetworkConnectivity NetworkConnectivitiy
{
get { return _networkConnectivity; }
set {
_networkConnectivity = value;
RaisePropertyChanged(() => NetworkConnectivitiy);
}
}
}
public class NetworkConnectivity
{
public bool HasNetworkConnection { get; set; }
}
}
I have a problem with this line of code:
public async Task UpdateContent()
{
if (_networkConnectivity.HasNetworkConnection)
{
SetInProgress();
await _trainingContentService.UpdateTrainingContentAsync();
await _applicationContentService.UpdateContent();
SetProgessComplete();
await FinishedUpdating();
}
return;
}
if (_networkConnectivity.HasNetworkConnection) is already null even though I set two way binding. I'm new to MVVM cross for this reason I don't know if my approach is correct.
Is there anyone who could provide some help?
Nick
You need to explicitly tell the binding what property you want to bind on your NetworkConnectivity like:
bindingSet.Bind(iOSNetworkConnectivitiy).For(v => v.HasNetworkConnection).To(vm => vm.NetworkConnectivitiy).TwoWay();
However, the binding does not have any way to get notified that your NetworkConnectivity class has gotten any of its values updated. Hence you would have to extend that class to have some kind of event where it can get notified.
Then, you would have to write and register a Target Binding class.
Lets say you simply implement INotifyPropertyChanged in your NetworkConnectivity class:
public class NetworkConnectivity : MvxNotifyPropertyChanged
{
private bool _hasNetworkConnection;
public bool HasNetworkConnection {
get { return _hasNetworkConnection; }
set {
_hasNetworkConnection = value;
RaisePropertyChanged();
}
}
}
Then you create the following class in your iOS project:
public class NetworkConnectivityTargetBinding
: MvxPropertyInfoTargetBinding<NetworkConnectivity>
{
public NetworkConnectivityTargetBinding(object target, PropertyInfo targetPropertyInfo)
: base(target, targetPropertyInfo)
{
var view = View;
if (view == null)
{
MvxBindingTrace.Trace(MvxTraceLevel.Error,
"NetworkConnectivity is null in NetworkConnectivityTargetBinding");
}
else
{
view.PropertyChanged += HandleValueChanged;
}
}
private void HandleValueChanged(object sender, System.EventArgs e)
{
var view = View;
if (view == null)
return;
FireValueChanged(view.HasNetworkConnection);
}
public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;
protected override void Dispose(bool isDisposing)
{
if (isDisposing)
{
var view = View;
if (view != null)
{
view.PropertyChanged -= HandleValueChanged;
}
}
base.Dispose(isDisposing);
}
}
Then in Setup.cs override FillTargetFactories:
protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
registry.RegisterPropertyInfoBindingFactory(typeof(NetworkConnectivityTargetBinding),
typeof(NetworkConnectivity), "HasNetworkConnection");
base.FillTargetFactories(registry);
}
Now the TwoWay binding should work. You should also be able to remove the .For(v => v.HasNetworkConnection) from you binding expression.
I have a MvxDialogFragment and I want to show that using ViewModel, similarly when a activity is showed from ViewModel using ShowViewModel. Is it possible? How can I do that?
This is my scenario: I have a page that contains a MvxListView and, when the user click in a listview item, I want to show a MvxDialogFragment.
My ListView layout:
<Mvx.MvxListView
android:id="#+id/lstViewTasks"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="1px"
android:clickable="true"
android:focusableInTouchMode="true"
android:choiceMode="multipleChoice"
android:layout_alignParentTop="true"
local:MvxBind="ItemsSource Tasks; ItemClick ItemClickCommand"
local:MvxItemTemplate="#layout/projectmytasksitem" />
My ListView ViewModel:
public class ProjectMyTasksViewModel : MvxViewModel
{
#region [Atributos privados]
private ProjectService _service;
#endregion
#region [Propriedades]
private IList<Task> _tasks;
public IList<Task> Tasks
{
get { return _tasks; }
set { _tasks = value; RaisePropertyChanged(() => Tasks); }
}
private bool _isListaVazia;
public bool IsListaVazia
{
get { return _isListaVazia; }
set { _isListaVazia = value; RaisePropertyChanged(() => IsListaVazia); }
}
private Task _selectedTask;
public Task SelectedTask
{
get { return _selectedTask; }
set { _selectedTask = value; RaisePropertyChanged(() => SelectedTask); }
}
private string _mensagemErro;
public string MensagemErro
{
get { return _mensagemErro; }
set { _mensagemErro = value; RaisePropertyChanged(() => MensagemErro); }
}
#endregion
#region [Commands]
private IMvxCommand _itenClickCommand;
public IMvxCommand ItemClickCommand
{
get
{
this._itenClickCommand = this._itenClickCommand ?? new MvxCommand<Task>(this.ExecuteItemClickCommand);
return _itenClickCommand;
}
}
#endregion
#region [Construtores]
public ProjectMyTasksViewModel()
{
_service = new ProjectService();
this.CriaListaTeste();
IsListaVazia = (Tasks.Count > 0) ? true : false;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteItemClickCommand(Task task)
{
Dictionary<string, Task> parametros = new Dictionary<string, Task>()
{
{"Task", task }
};
this.ShowViewModel<TaskViewModel>(parametros);
}
#endregion
#region [Métodos]
public void CriaListaTeste()
{
Tasks = new List<Task>();
for (int indiceProjeto = 1; indiceProjeto <= 10; indiceProjeto++)
{
Tasks.Add(new Task { Name = $"Tarefa {indiceProjeto}", StartDate = DateTime.Now, FinishDate = DateTime.Now, IsCompleted = false });
}
}
#endregion
}
My Listview Activity:
[Activity(Label = "My Task",
ConfigurationChanges = ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait)]
public class ProjectMyTasksView : MvxActivity
{
public new ProjectMyTasksViewModel viewModel
{
get { return (ProjectMyTasksViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetContentView(Resource.Layout.ProjectMyTasksView);
}
}
My Dialog Fragment:
public class ProjectMyTaskDialog : MvxDialogFragment<TaskViewModel>
{
public override Dialog OnCreateDialog(Bundle savedState)
{
base.EnsureBindingContextSet(savedState);
this.BindingInflate(Resource.Layout.ProjectMyTasksDialog, null);
return base.OnCreateDialog(savedState);
}
}
My Dialog Fragment ViewModel:
public class TaskViewModel : BaseViewModel<TaskService, Task>
{
#region [Atributos Privados]
private readonly IMvxPictureChooserTask _pictureChooserTask;
#endregion
#region [Commands]
private MvxCommand _chooseImageCommand;
public MvxCommand ChooseImageCommand
{
get
{
_chooseImageCommand = _chooseImageCommand ?? new MvxCommand(ExecuteChooseImageCommand);
return _chooseImageCommand;
}
}
private MvxCommand _takePictureCommand;
public MvxCommand TakePictureCommand
{
get
{
_takePictureCommand = _takePictureCommand ?? new MvxCommand(ExecuteTakePictureCommand);
return _takePictureCommand;
}
}
private MvxCommand _completeTaskCommand;
public MvxCommand CompleteTaskCommand
{
get
{
_completeTaskCommand = _completeTaskCommand ?? new MvxCommand(ExecuteCompleteTaskCommand);
return _completeTaskCommand;
}
}
#endregion
#region [Construtores]
public TaskViewModel(IMvxPictureChooserTask pictureChooserTask)
{
_pictureChooserTask = pictureChooserTask;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteChooseImageCommand()
{
_pictureChooserTask.ChoosePictureFromLibrary(400, 95, OnImage, () => { });
}
private void ExecuteTakePictureCommand()
{
_pictureChooserTask.TakePicture(400, 95, OnImage, () => { });
}
public void ExecuteCompleteTaskCommand()
{
throw new NotImplementedException();
}
#endregion
#region [Métodos]
public void Init(Dictionary<string, Task> parametros)
{
Objeto = parametros["Task"];
}
private void OnImage(Stream imageStream)
{
var memoryStream = new MemoryStream();
imageStream.CopyTo(memoryStream);
Objeto.Image = memoryStream.ToArray();
}
#endregion
public class Parametros
{
public string TaskJson { get; set; }
}
}
There is no presenter for DialogFragments.
Instead you could have instantiate the Command from the Activity or have a callback into the Activity which determines what to do when the command is called, i.e. displaying the Dialog.
So for a simple example:
public class MyViewModel : MvxViewModel
{
public Action ShowTaskCommandAction {get;set;}
private MvxCommand _showTaskCommand;
public ICommand ShowTaskCommand =>
_showTaskCommand = _showTaskCommand ?? (_showTaskCommand = new MvxCommand(DoShowTaskCommand));
private void DoShowTaskCommand()
{
CommandAction?.Invoke();
// do other stuff here...
}
}
Then in your Activity or Fragment:
public class MyActivity : MvxActivity<MyViewModel>
{
public void OnCreate(Bundle _)
{
base.OnCreate(_);
ViewModel.ShowTaskCommandAction = () => {
var dialogFragment = new ProjectMyTaskDialog() {
DataContext = task
});
dialogFragment.Show(FragmentManager);
};
// whatever else code
}
}
I have a list item which has more or less around 10 objects. I could able to detect which item is selected and also I sending this item properties into the DetailViewModel,I am using messageprotocol in mvvmcross.
I could able to observe changes in the MainViewModel when user enters new value in the edittext in DetailViewModel.
I wonder how I am going to put these values back into the selected item and update list.
MainViewModel
private readonly IMvxMessenger _messenger;
private readonly MvxSubscriptionToken _token;
private MainViewModel _selectedItem;
public MainViewModel SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
ShowViewModel<DetailViewModel>(
new DetailViewModel.Parameter
{
Age= _selectedItem.Age,
Category = _selectedItem.Category,
});
RaisePropertyChanged(() => SelectedItem);
}
}
public MainViewModel(IMvxMessenger messenger) {
_messenger = messenger;
_token = messenger.Subscribe<SelectedItemMessage>(OnMessageReceived);;
}
private void OnMessageReceived(SelectedItemMessage obj)
{
// I could observe the DetailView Changes in the MainViewModel
// I wonder how to put these value back to selectedItem
double? Age = obj.Age;
int? Category= obj.Category;
}
public virtual ICommand ItemSelected
{
get{ return new MvxCommand<TestViewModel>(item =>{ SelectedItem = item;});
}
}
private ObservableCollection<TestViewModel> _testViews;
private ObservableCollection<WellTestViewModel> _allTestItemViews;
public void Init(string Id)
{
List<Test> allTests = new List<Test>();
allTests = _TestService.GetAllTestById(Id);
foreach (var test in allTests)
{
_testViews.Add(TestViewModel.CreateViewModel(test, this));
}
_allTestItemViews = _testViews;
}
TestViewModel
public static TestViewModel CreateViewModel(Test entity, MainViewModel parent = null)
{
if (entity == null)
{
return null;
}
return new TestViewModel(parent)
{
Age = entity.Age,
Category= entity.Category,
};
}
public TestViewModel()
{
// parameterless constructor
}
readonly MainViewViewModel _mainViewModel ;
public TestViewModel(MainViewViewModel mainViewViewModel)
{
_mainViewModel = mainViewViewModel;
}
DetailViewModel
private readonly IMvxMessenger _messenger;
public class Parameter
{
public double? Age{ get; set; }
public int? Category { get; set; }
}
public void Init(Parameter param)
{
Age= param.Age;
Category= param.Category;
}
public DetailViewModel(IMvxMessenger messenger) {
_messenger = messenger;
}
public void UpdateMethod() {
var message = new SelectedItemMessage(this, age, category);
_messenger.Publish(message, typeof(SelectedItemMessage));
}
SelectedItemMessage
public SelectedItemMessage(object sender, double? age, int? category) : base(sender)
{
Age = age;
Category = category;
}
public double? Age { get; set; }
public int? Category{ get; set; }
}
Just use your _selectedItem and set the properties on it.
private void OnMessageReceived(SelectedItemMessage obj)
{
_selectedItem.Age = obj.Age;
_selectedItem.Category= obj.Category;
}
You need to update the collection inside the OnMessageReceived method:
var item = _allTestItemViews.FirstOrDefault(i => i.Id == id);
if (item != null)
{
item.Age = age;
item.Category = category;
}
You need to add Id to your model class so that you can uniquely identify the item you need to update.
The following code provides the runtime error in the question title. Though, when I comment out the OneWayBind() call within the MainWindow constructor, the app runs without error. Any ideas?
The Window
public partial class MainWindow : Window, IViewFor<MainViewModel>
{
public MainWindow()
{
ViewModel = new MainViewModel();
InitializeComponent();
this.OneWayBind(ViewModel, x => x.ContentItems, x => x.panelDemo.ItemsSource);
}
public MainViewModel ViewModel
{
get { return (MainViewModel)GetValue(ViewModelProperty); }
set { SetValue(ViewModelProperty, value); }
}
public static readonly DependencyProperty ViewModelProperty =
DependencyProperty.Register("ViewModel", typeof(MainViewModel), typeof(MainWindow), new PropertyMetadata(null));
object IViewFor.ViewModel
{
get { return ViewModel; }
set { ViewModel = (MainViewModel)value; }
}
}
The Class
public class ContentItem
{
public BitmapImage Image { get; set; }
public string Name { get; set; }
}
The ViewModel
public class MainViewModel : ReactiveObject
{
string _Directory;
public string Directory
{
get { return _Directory; }
set { this.RaiseAndSetIfChanged(x => x.Directory, value); }
}
bool _IsBusy;
public bool IsBusy
{
get { return _IsBusy; }
set { this.RaiseAndSetIfChanged(x => x.IsBusy, value); }
}
ObservableAsPropertyHelper<IList<ContentItem>> _ContentItems;
public IList<ContentItem> ContentItems
{
get { return _ContentItems.Value; }
}
public MainViewModel()
{
this.WhenAny(x => x.Directory, x => x.Value)
.Do(_ => IsBusy = true)
.Select(GetImages)
.Do(_ => IsBusy = false);
}
IObservable<IList<ContentItem>> GetImages(string directory)
{
return new DirectoryInfo(directory).GetFiles().ToList().ToObservable()
.Select(x => new ContentItem
{
Image = new BitmapImage(new Uri(x.FullName)),
Name = x.Name
}).ToList();
}
}
Thank you so much! The only thing I wish of ReactiveUI 4.5.0 is that it have current WPF implementation samples! They're all six months or more outdated!