Changing TabbedPage binding property from a (different) class - Xamarin.Forms - c#

My TabbedPage uses a Binding Property, which is defined in the tabbed page's ViewModel, for showing a Badge text.
I am setting the badge property when initializing the view (actually when it (re)appears). However, sometimes the badge text is changing from outside of my ViewModel(s), this is because I have a SignalR method which is called when a new message is being added by another application.
Though, when this happens the OnAppearing method of my tabbed viewmodel is obviously not called. So the question is, how can I 'notify' the tabbedpage viewmodel that the badge text should be changed.
I think the (best) way to do this is using somekind of Event. Since all of my ViewModels inherit from a 'ViewModelBase' I could implement the event notification / change in the ViewModelBase and override the property in my TabbedPage ViewModel.
Though, sadly my knowledge about using Events / EventArgs is limited and the stuff I found about it is not working.
Is using EventArgs the best way to solve this problem? And if so, could anyone give any pointers how to implement it properly.
*On a side-note, I am also using Prism
My TabbedPage ViewModel:
public class RootTabbedViewModel : ViewModelBase, IPageLifecycleAware
{
private readonly INavigationService _navigationService;
private int _messageCount;
public RootTabbedViewModel(INavigationService navigationService)
: base(navigationService)
{
_navigationService = navigationService;
}
public int MessageCount
{
get { return _messageCount; }
set { SetProperty(ref _messageCount, value); }
}
public void OnDisappearing()
{
}
void IPageLifecycleAware.OnAppearing()
{
// (omitted) Logic for setting the MessageCount property
}
}
ViewModelVase:
public class ViewModelBase : BindableBase, IInitialize, IInitializeAsync, INavigationAware, IDestructible, IActiveAware
{
public event EventHandler MessageAddedEventArgs; // this should be used to trigger the MessageCount change..
protected INavigationService NavigationService { get; private set; }
public ViewModelBase(INavigationService navigationService)
{
NavigationService = navigationService;
Connectivity.ConnectivityChanged += Connectivity_ConnectivityChanged;
IsNotConnected = Connectivity.NetworkAccess != NetworkAccess.Internet;
}
private bool _isNotConnected;
public bool IsNotConnected
{
get { return _isNotConnected; }
set { SetProperty(ref _isNotConnected, value); }
}
~ViewModelBase()
{
Connectivity.ConnectivityChanged -= Connectivity_ConnectivityChanged;
}
async void Connectivity_ConnectivityChanged(object sender, ConnectivityChangedEventArgs e)
{
IsNotConnected = e.NetworkAccess != NetworkAccess.Internet;
if (IsNotConnected == false)
{
await DataHubService.Connect();
}
}
public virtual void Initialize(INavigationParameters parameters)
{
}
public virtual void OnNavigatedFrom(INavigationParameters parameters)
{
}
public virtual void OnNavigatedTo(INavigationParameters parameters)
{
}
public virtual void Destroy()
{
}
public virtual Task InitializeAsync(INavigationParameters parameters)
{
return Task.CompletedTask;
}
}
SignalR Datahub which should trigger the event:
public static class DataHubService2
{
// .. omitted some other SignalR specific code
public static async Task Connect()
{
try
{
GetInstanse();
hubConnection.On<Messages>("ReceiveMessage", async (message) =>
{
if(message != null)
{
// event that message count has changed should be triggered here..
}
});
}
catch (Exception ex)
{
// ...
}
}
}

As pointed out by #Jason, this specific problem is a good use case for using the MessagingCenter.
In the end the implementation looks as following:
public static class DataHubService2
{
// .. omitted some other SignalR specific code
public static async Task Connect()
{
try
{
GetInstanse();
hubConnection.On<Messages>("ReceiveMessage", async (message) =>
{
if(message != null)
{
MessagingCenter.Send("UpdateMessageCount", "Update");
}
});
}
catch (Exception ex)
{
// ...
}
}
}
public class RootTabbedViewModel : ViewModelBase, IPageLifecycleAware
{
private readonly INavigationService _navigationService;
private int _messageCount;
public RootTabbedViewModel(INavigationService navigationService)
: base(navigationService)
{
_navigationService = navigationService;
MessagingCenter.Subscribe<string>("UpdateMessageCount", "Update", async (a) =>
{
await UpdateMessageCount();
});
}
public int MessageCount
{
get { return _messageCount; }
set { SetProperty(ref _messageCount, value); }
}
public void OnDisappearing()
{
}
void IPageLifecycleAware.OnAppearing()
{
UpdateMessageCount();
}
async Task UpdateMessageCount()
{
int messageCount = await App.Database.GetNewMessageCountAsync();
MessageCount = messageCount.ToString();
}
}

Related

Xamarin Override RemoteControlReceived in Dependency Injection

I am trying to override the RemoteControlRecieved method of the UIApplication and getting the following error:
NSInternalInconsistencyException Reason: There can only be one UIApplication instance.
I understand the issue but have not idea how to solve it. I have a StreamingService class which implements the UIApplication and IStreaming interface. All of my AVPlayer functionality is in this class. the StreamingViewModel class calls the
DependencyService.Get<IStreaming>().Play().
When this line is called I get the above error. I am not sure how to override RemoteControlRecieved from either the StreamingService or the StreamingViewModel class.
any help with code samples is greatly appreciated.
Classes below
public class StreamingViewModel : INotifyPropertyChanged
{
public bool DisplayPlay { get => !isPlaying; }
public bool DisplayPauseStop { get => isPlaying; }
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
bool isPlaying;
bool IsPlaying
{
get => isPlaying;
set
{
isPlaying = value;
// Notify the property has changed
OnPropertyChanged("DisplayPlay");
OnPropertyChanged("DisplayPauseStop");
}
}
public void Play()
{
DependencyService.Get<IStreaming>().Play();
IsPlaying = true;
}
public void Pause()
{
DependencyService.Get<IStreaming>().Pause();
IsPlaying = false;
}
public void Stop()
{
DependencyService.Get<IStreaming>().Stop();
IsPlaying = false;
}
}
Class StreamingService
[assembly: Xamarin.Forms.ExportRenderer(typeof(MainPage), typeof(StreamingService))]
[assembly: Dependency(typeof(StreamingService))]
namespace test.iOS
{
public class StreamingService : PageRenderer, IStreaming
{
AVPlayer player;
bool isPrepared;
string dataSource = "https://stream.voxx.pro/radio/8260/radio.mp3";
public override void ViewDidLoad()
{
Console.WriteLine("StreamService ViewDidLoad");
base.ViewDidLoad();
}
public StreamingService()
{
Console.WriteLine("StreamService Default Constructor");
}
public void Play()
{
Console.WriteLine("Play");
if (!isPrepared || player == null)
player = AVPlayer.FromUrl(NSUrl.FromString(dataSource));
//Audio player Notification in lock screen
MPNowPlayingInfo nowPlayingInfo;
nowPlayingInfo = new MPNowPlayingInfo();
nowPlayingInfo.Artist = "Radio Caravan";
nowPlayingInfo.Title = "Join The Caravan";
// Register for receiving controls from lock screen and controlscreen
MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = nowPlayingInfo;
//var command = MPRemoteCommandCenter.Shared;
//command.PlayCommand.Enabled = true;
//command.PauseCommand.Enabled = true;
//command.NextTrackCommand.Enabled = false;
//command.PreviousTrackCommand.Enabled = false;
isPrepared = true;
player.Play();
base.BecomeFirstResponder();
//To listen changes in lock screen
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
}
public void Pause()
{
player.Pause();
}
public void Stop()
{
player.Dispose();
isPrepared = false;
}
public override void RemoteControlReceived(UIEvent theEvent)
{
Console.WriteLine("Remote Control Received");
base.RemoteControlReceived(theEvent);
if (theEvent.Subtype == UIEventSubtype.RemoteControlPause)
{
Console.WriteLine("Remote Pause");
player.Pause();
}
else if (theEvent.Subtype == UIEventSubtype.RemoteControlPlay)
{
Console.WriteLine("Remote Play");
player.Play();
}
}
}
}
MainPage.cs
namespace test
{
public partial class MainPage : ContentPage
{
private StreamingViewModel ViewModel { get { return (StreamingViewModel)this.BindingContext; } }
public MainPage()
{
InitializeComponent();
On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea(true);
BindingContext = new StreamingViewModel();
}
// Callbacks to images tapped
private void Play_tapped(object sender, EventArgs e)
{
ViewModel.Play();
}
private void Pause_tapped(object sender, EventArgs e)
{
ViewModel.Pause();
}
private void Stop_tapped(object sender, EventArgs e)
{
ViewModel.Stop();
}
}
}
Interface: IStreaming
public interface IStreaming
{
void Play();
void Pause();
void Stop();
}
NSInternalInconsistencyException Reason: There can only be one UIApplication instance.
You could custom PageRenderer to override RemoteControlReceived method to check whether it works. Because this will use the existing UIApplication.
About isPlaying property, you could use Bindable Properties to define in CustomPage.
About Play/Pause/Stop method, you could use MessagingCenter to send Message from Forms to CustomPageRenderer.
For example, part code of CustomPage as follows:
public partial class CustomPage: ContentPage
{
public CustomPage()
{
InitializeComponent();
}
public static readonly BindableProperty IsPlayingProperty = BindableProperty.Create("IsPlaying", typeof(bool), typeof(CustomPage), null);
public bool IsPlaying
{
get { return (bool)GetValue(IsPlayingProperty); }
set { SetValue(IsPlayingProperty, value); }
}
public void Play()
{
MessagingCenter.Send<object, string>(this, "PlayControl", "Play");
IsPlaying = true;
}
public void Pause()
{
MessagingCenter.Send<object, string>(this, "PlayControl", "Pause");
IsPlaying = false;
}
public void Stop()
{
MessagingCenter.Send<object, string>(this, "PlayControl", "Stop");
IsPlaying = false;
}
}
The part code of CustomPageRenderer as follows:
[assembly: Xamarin.Forms.ExportRenderer(typeof(CustomPage), typeof(CustomPageRenderer))]
namespace XamarinForms20.iOS
{
public class CustomPageRenderer : PageRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
//...
MessagingCenter.Subscribe<object, string>(this, "PlayControl", (sender, arg) =>
{
if(arg == "Play")
{
//...
}else if (arg == "Pause")
{
//...
}else if (arg == "Stop")
{
//...
}
});
}
public override void RemoteControlReceived(UIEvent theEvent)
{
base.RemoteControlReceived(theEvent);
if (theEvent.Subtype == UIEventSubtype.RemoteControlPlay)
player.Play();
else if (theEvent.Subtype == UIEventSubtype.RemoteControlPause)
player.Pause();
}
}
}
===================================Update================================
You could have a try with adding NSNotificationCenter in ViewDidload method for AVAudioSession.InterruptionNotification.
public override void ViewDidLoad()
...
NSObject _notificationHandle = NSNotificationCenter.DefaultCenter.AddObserver(AVAudioSession.InterruptionNotification, HandleNotification);
...
private void HandleNotification(NSNotification notification)
{
// Do something
NSDictionary userinfo = notification.UserInfo;
NSNumber number = (NSNumber)userinfo.ValueForKey(new NSString("AVAudioSessionInterruptionTypeKey"));
int value = (int)number.NIntValue;
if(value == 1)
{
// pause
}else if(value == 0)
{
// countinue to play
AVAudioSession.SharedInstance().SetActive(true);
}
}

How to prevent Xamarin forms, a custom menu and WebView renderer with EvaluateJavascript from freezing?

I have created a custom menu item which appears in the default menu which pops up when selecting text on my custom WebView.
On clicking on the menu item it calls EvaluateJavascript to get the selected WebView text, and then passes the text to another page.
However after performing this action once or twice, some text on certain areas of the screen start to become unresponsive to clicks eg. text on the parts of the WebView become unselectable, clicks on that part of the screen on other pages becomes unresponsive and even the soft keyboard becomes unclickable in some spots. If this continues for a while sometimes my app will then suddenly freeze the entire operating system and I have to soft reset my phone. It appears that there maybe some serious memory leakage going on.
I create my custom menu item in the MainActivity class:
public override void OnActionModeStarted(ActionMode mode)
{
if (Root.IsCurrentPageType<DictPage>() && DictP.IsWebViewFocused())
{
IMenu menu = mode.Menu;
menu.Add("To Notes");
menu.GetItem(0).SetOnMenuItemClickListener(new MyMenuItemOnMenuItemClickListener(this, mode));
}
base.OnActionModeStarted(mode);
}
It is then handled in the Listener class...
public class MyMenuItemOnMenuItemClickListener : Java.Lang.Object, IMenuItemOnMenuItemClickListener
{
private MainActivity mContext;
ActionMode _mode;
public MyMenuItemOnMenuItemClickListener(MainActivity activity, ActionMode mode)
{
this.mContext = activity;
_mode = mode;
}
public bool OnMenuItemClick(IMenuItem item)
{
WEB.CopyToMainNotes();
Device.BeginInvokeOnMainThread(() =>
{
//close menu if clicked
_mode?.Finish();
});
return true;
}
}
...which calls CopyToMainNotes on my derived WebView class and its associated Renderer and EventHandler classes:
public class WebViewEx : Xamarin.Forms.WebView
{
public static WebViewEx WEB;
//Namespace
//YourClass
public event WebViewExEventHandler CallNativeMethodEvent;
public void CallNativeMethod(WebViewExEventType type)
{
WebViewExEventArgs e = new WebViewExEventArgs();
e.EventType = type;
CallNativeMethodEvent?.Invoke(this, e);
}
public WebViewEx()
{
WEB = this;
}
public void CopyToMainNotes()
{
Device.BeginInvokeOnMainThread(() =>
{
CallNativeMethod(WebViewExEventType.copyToMainNotes);
});
}
}
public delegate void WebViewExEventHandler(object sender, WebViewExEventArgs e);
public class WebViewExEventArgs : EventArgs
{
public enum WebViewExEventType { copyToMainNotes };
public WebViewExEventType EventType = WebViewExEventType.copyToMainNotes;
public WebViewExEventArgs() : base()
{
}
}
public class WebViewExRenderer : WebViewRenderer
{
public WebViewExRenderer(Android.Content.Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (Control != null)
{
WebViewEx ex = e.NewElement as WebViewEx;
ex.CallNativeMethodEvent += WebViewEx_CallNativeMethodEvent;
}
}
internal class JavascriptCallback : Java.Lang.Object, IValueCallback
{
public JavascriptCallback(Action<string> callback)
{
_callback = callback;
}
private Action<string> _callback;
public void OnReceiveValue(Java.Lang.Object value)
{
_callback?.Invoke(Convert.ToString(value));
}
}
private void WebViewEx_CallNativeMethodEvent(object sender, WebViewExEventArgs e)
{
switch (e.EventType)
{
case WebViewExEventType.copyToMainNotes:
{
CopyToMainNotes();
break;
}
}
}
public void CopyToMainNotes()
{
string script = "(function(){ return window.getSelection().toString()})()";
var response = string.Empty;
Control?.EvaluateJavascript(script, new JavascriptCallback((r) =>
{
response = r;
Device.BeginInvokeOnMainThread(() =>
{
DPage.CopyThisTextToAnotherPage(response.ToString().Trim('\"'));
});
}));
}
}
The CopyToMainNotes method above is where the EvaluateJavascript takes place and the selected text finally gets sent to another page.
Any ideas where I might be going wrong here? Thanks in advance!

MvxAppCompatDialogFragment cancellation via Back button is not completely working

Closing a MvxAppCompatDialogFragment via the back button doesn't seem to work completely. The button I clicked to trigger the dialog remains disabled after the dialog is dismissed. It's almost like the Task is stuck. If I change to MvxDialogFragment then the back button will close the dialog as expected, and the button I clicked to trigger the dialog is enabled again after the dialog is dismissed. I'm trying to use MvxAppCompatDialogFragment because I'm using MvxAppCompatActivity. Am I doing something wrong or is this a bug in MvvmCross 5.2.1?
Here is the ViewModel:
public class ConfirmationViewModel : MvxViewModel<ConfirmationConfiguration, bool?>, IMvxLocalizedTextSourceOwner
{
private readonly IMvxNavigationService _mvxNavigationService;
public ConfirmationViewModel(IMvxNavigationService mvxNavigationService)
{
_mvxNavigationService = mvxNavigationService;
}
public override void Prepare([NotNull] ConfirmationConfiguration parameter)
{
if (parameter == null) throw new ArgumentNullException(nameof(parameter));
Title = parameter.Title;
Body = parameter.Body;
PositiveCommandText = !string.IsNullOrEmpty(parameter.YesCommandText)
? parameter.YesCommandText
: LocalizedTextSource.GetText("Yes");
NegativeCommandText = !string.IsNullOrEmpty(parameter.NoCommandText)
? parameter.NoCommandText
: LocalizedTextSource.GetText("No");
}
private bool? _confirmationResult;
public bool? ConfirmationResult
{
get => _confirmationResult;
private set => SetProperty(ref _confirmationResult, value);
}
private string _title;
public string Title
{
get => _title;
set => SetProperty(ref _title, value);
}
private string _body;
public string Body
{
get => _body;
set => SetProperty(ref _body, value);
}
private string _positiveCommandText;
public string PositiveCommandText
{
get => _positiveCommandText;
set => SetProperty(ref _positiveCommandText, value);
}
private string _negativeCommandText;
public string NegativeCommandText
{
get => _negativeCommandText;
set => SetProperty(ref _negativeCommandText, value);
}
private IMvxAsyncCommand _yesCommand;
public IMvxAsyncCommand PositiveCommand => _yesCommand ?? (_yesCommand = new MvxAsyncCommand(OnPositiveCommandAsync));
private async Task OnPositiveCommandAsync()
{
ConfirmationResult = true;
await _mvxNavigationService.Close(this, ConfirmationResult);
}
private IMvxAsyncCommand _noCommand;
public IMvxAsyncCommand NegativeCommand => _noCommand ?? (_noCommand = new MvxAsyncCommand(OnNegativeCommandAsync));
private async Task OnNegativeCommandAsync()
{
ConfirmationResult = false;
await _mvxNavigationService.Close(this, ConfirmationResult);
}
public IMvxLanguageBinder LocalizedTextSource => new MvxLanguageBinder("", GetType().Name);
public IMvxLanguageBinder TextSource => LocalizedTextSource;
}
public class ConfirmationConfiguration
{
public string Title { get; set; }
public string Body { get; set; }
public string YesCommandText { get; set; }
public string NoCommandText { get; set; }
}
Here is the View:
[MvxDialogFragmentPresentation(Cancelable = true)]
[Register(nameof(ConfirmationFragment))]
public class ConfirmationFragment : MvxAppCompatDialogFragment<ConfirmationViewModel>
{
public ConfirmationFragment()
{
RetainInstance = true;
}
public ConfirmationFragment(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
RetainInstance = true;
}
public override Dialog OnCreateDialog(Bundle savedInstanceState)
{
var builder = new AlertDialog.Builder(Activity)
.SetTitle(ViewModel.Title)
.SetMessage(ViewModel.Body)
.SetPositiveButton(ViewModel.PositiveCommandText, OnPositiveButton)
.SetNegativeButton(ViewModel.NegativeCommandText, OnNegativeButton);
return builder.Create();
}
private async void OnNegativeButton(object sender, DialogClickEventArgs e)
{
if (ViewModel.NegativeCommand.CanExecute())
{
await ViewModel.NegativeCommand.ExecuteAsync();
}
}
private async void OnPositiveButton(object sender, DialogClickEventArgs e)
{
if (ViewModel.PositiveCommand.CanExecute())
{
await ViewModel.PositiveCommand.ExecuteAsync();
}
}
}
I'm navigating to the dialog like this:
var confirmation = await Mvx.Resolve<IMvxNavigationService>().Navigate<ConfirmationViewModel, ConfirmationConfiguration, bool?>(
new ConfirmationConfiguration()
{
Body = "Hello, World!",
Title = "Testing"
});
If I change the base class from MvxAppCompatDialogFragment to MvxDialogFragment then it all works as expected.
This was indeed an issue in MvvmCross v5.2.1 (thanks for reporting!). As a workaround for now you can add this code in your DialogFragment class:
public override void OnCancel(IDialogInterface dialog)
{
base.OnCancel(dialog);
ViewModel?.ViewDestroy();
}
public override void DismissAllowingStateLoss()
{
base.DismissAllowingStateLoss();
ViewModel?.ViewDestroy();
}
public override void Dismiss()
{
base.Dismiss();
ViewModel?.ViewDestroy();
}
I've looked into this. What happens is that when you press the back button it closes the View without calling the NavigationSerivce.Close(). This prevents the result Task to be called and either set or cancel the action. I'm not sure if this is a bug or just behavior. A workaround could be to call Close from ConfirmationViewModel ViewDissapearing, or cancel the Task yourself.

MvvmCross - handle button click in viewmodel

I'm new to xamarin and mvvmcross and I would like to wire up a simple button click from my ios project to my viewmodel.
using System;
using MvvmCross.Binding.BindingContext;
using MvvmCross.iOS.Views;
using Colingual.Core.ViewModels;
namespace Colingual.iOS
{
public partial class LoginView : MvxViewController
{
public LoginView() : base("LoginView", null)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
var set = this.CreateBindingSet<LoginView, LoginViewModel>();
set.Bind(Username).To(vm => vm.Username);
set.Bind(Password).To(vm => vm.Password);
set.Bind(btnLogin).To(vm => vm.MyAwesomeCommand);
set.Apply();
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
}
I would like to wire up btnlogin to myawesomecommand.
using MvvmCross.Core.ViewModels;
namespace Colingual.Core.ViewModels
{
public class LoginViewModel : MvxViewModel
{
readonly IAuthenticationService _authenticationService;
public LoginViewModel(IAuthenticationService authenticationService)
{
_authenticationService = authenticationService;
}
string _username = string.Empty;
public string Username
{
get { return _username; }
set { SetProperty(ref _username, value); }
}
string _password = string.Empty;
public string Password
{
get { return _password; }
set { SetProperty(ref _password, value); }
}
public bool AuthenticateUser() {
return true;
}
MvxCommand _myAwesomeCommand;
public IMvxCommand MyAwesomeCommand
{
get
{
DoStuff();
return _myAwesomeCommand;
}
}
void DoStuff()
{
string test = string.Empty;
}
}
}
As you can see I've got mvxCommand with the name of MyAwesomecommand but I want to handle some logic from a button click in my other project. Anyone know what I should do?
I've done more looking around and found an answer here.
MvxCommand _myAwesomeCommand;
public IMvxCommand MyAwesomeCommand
{
get { return new MvxCommand(DoStuff); }
}
void DoStuff()
{
string test = string.Empty;
}
The idea is to have your mvxcommand getter which returns a new command that takes the method as a parameter.
When clicking the button btnLogin, you can access void DoStuff in viewmodel.

How to resolve view not closing on .Close()?

I've added a DialogService in order to open a ProductView, so far the ShowDetailDialog() is working as expected.
Issue:
I call Close() on the ProductView, the view isn't closed. I debugged this issue by setting a break point on the call to the dialog service close method.
When I stepped through the code, the null check shows that productView is null, which prevents Close() from being called.
Does anyone have idea why productView is null? (although it's showing data on the view)
DialogService:(hosts the Show and Close methods)
namespace MongoDBApp.Services
{
class DialogService : IDialogService
{
Window productView = null;
ProductView _productView;
public DialogService()
{
_productView = new ProductView();
}
public void CloseDetailDialog()
{
if (productView != null)
productView.Close();
}
public void ShowDetailDialog()
{
_productView.ShowDialog();
}
}
}
ProductViewModel: (summary of ProductVM, calls the close method on SaveCommand)
private void SaveProduct(object product)
{
_dialogService.CloseDetailDialog();
Messenger.Default.Send<ProductModel>(SelectedProduct);
}
CustomerOrdersViewmodel: (Where the ShowDetailDialog() is called initially)
private void EditOrder(object obj)
{
Messenger.Default.Send<ProductModel>(SelectedProduct);
_dialogService.ShowDetailDialog();
}
This is how I have always closed my windows.
Here would be my command:
class CancelCommand : ICommand
{
private NewTruckViewModel newTruck;
public CancelCommand(NewTruckViewModel vm)
{
newTruck = vm;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
newTruck.Cancel();
}
}
Here is my view Model and the method that gets called from my command:
private NewTruck myWnd; //View Declaration
//Ctor where I set myView (myWnd) equal to a view that is passed in.
public NewTruckViewModel(ObservableCollection<Truck> Trucks, NewTruck wnd, bool inEditTruck)
{
myEngine.stopHeartBeatTimer();
editTruck = inEditTruck;
myWnd = wnd;
SaveTruckCommand = new SaveTruckCommand(this);
CancelCommand = new CancelCommand(this);
ClearCommand = new ClearCommand(this);
SetLevel1MTCommand = new SetLevel1MTCommand(this);
SetLevel2MTCommand = new SetLevel2MTCommand(this);
SetLevel3MTCommand = new SetLevel3MTCommand(this);
SetLevel1FLCommand = new SetLevel1FLCommand(this);
SetLevel2FLCommand = new SetLevel2FLCommand(this);
SetLevel3FLCommand = new SetLevel3FLCommand(this);
myTrucks = Trucks;
}
public void Cancel()
{
myWnd.Close();
}
This works for me.
I resolved the issue by implementing an IDialogService on the View. Then calling the Show() and Close() methods from the ViewModel.
Solution:
Interface:
public interface IDialogService
{
void CloseDialog();
void ShowDialog(EditProductViewModel prodVM);
}
View:
public partial class ProductView : Window, IDialogService
{
public ProductView()
{
InitializeComponent();
this.DataContext = new EditProductViewModel(this);
}
public void CloseDialog()
{
if (this != null)
this.Visibility = Visibility.Collapsed;
}
public void ShowDialog(EditProductViewModel prodVM)
{
this.DataContext = prodVM;
this.Show();
}
private void Window_Closed(object sender, EventArgs e)
{
this.Visibility = Visibility.Collapsed;
}
}
ViewModel #1:
private IDialogService _dialogService;
public CustomerOrdersViewModel(IDialogService dialogservice)
{
this._dialogService = dialogservice;
}
private void EditOrder(object obj)
{
EditProductViewModel pvm = new EditProductViewModel(_dialogService);
pvm.Present(pvm);
Messenger.Default.Send<ProductModel>(SelectedProduct);
}
ViewModel #2:
private IDialogService _dialogService;
public EditProductViewModel(IDialogService dialogService)
{
this._dialogService = dialogService;
}
private void SaveProduct(object product)
{
SelectedProduct = SelectedProductTemp;
_dialogService.CloseDialog();
}
public void Present(EditProductViewModel prodVM)
{
_dialogService.ShowDialog(prodVM);
}

Categories

Resources