We are developing a UWP app using Template10. The app displays Cost, Net, Tax and Total correctly. Tax and Total are calculated properties in the ViewModel. However when Net is updated in the ViewModel, Tax and Total are updated in the ViewModel but not updated in the View. The Xaml:
<TextBlock
Text="{x:Bind ViewModel.Net,Mode=OneWay}"
/>
<TextBlock
Text="{x:Bind ViewModel.Tax,Mode=OneWay}"
/>
<TextBlock
Text="{x:Bind ViewModel.Total,Mode=OneWay}"
/>
The ViewModel:
public class ViewModel : ViewModelBase
{
decimal? _Net = default(decimal?);
public decimal? Net
{
get
{
return _Net;
}
set
{
if (value == 0) value = null;
Set(ref _Net, value);
}
}
decimal? _TaxRate = default(decimal?);
public decimal? TaxRate { get { return _TaxRate; } set { Set(ref _TaxRate, value); } }
public decimal? Tax
{
get
{
return TaxRate / 100 * Net;
}
}
public decimal? Total { get { return Net + Tax; } }
We have a command in the ViewModel that edits Net
DelegateCommand _SetDiscount;
public DelegateCommand SetDiscount
=> _SetDiscount ?? (_SetDiscount = new DelegateCommand(() =>
{
// for simplicity deleted calculations for the newNet
this.Net = newNet ?? 0;
}, () => true));
Net, Tax and Total are correctly updated in the ViewModel. Net is correctly updated in the View. Why are Tax and Total not updated in the View?
They are not updated in the View because you are not informing it about the change. Your Set() method has inside a RaisePropertyChanged(string) method (or something similar invoking PropertyChanged event) so your Net value change is being shown, just add in Net setter change information for the two other:
public decimal? Net
{
get
{
return _Net;
}
set
{
if (value == 0) value = null;
Set(ref _Net, value);
RaisePropertyChanged(nameof(Total));
RaisePropertyChanged(nameof(Tax));
}
}
Related
I have an application in .Net Maui that uses a collection view with an entry field and after the collection view one static entry field. If you are currently focused on the first entry in the collection view and hit tab or enter it will not navigate to the next entry in the collection view and focus on the static entry field. I need to find the best way to have the entry focus on the next entry in the collection view on complete.
I have tried changing the return type of the collection view entry field to Next and also tried the community toolkit SetFocusOnEntryCompletedBehavior function and both result in the same behavior of not navigating to the next entry from the collection view. Very similar to this issue that doesnt seem to be resolved. MAUI - CollectionView jump / focus to next entry
I found a workaround for you. You could try the following code:
Step1 Create a custom control , let's call it MyEntry (MyEntry.cs) which subclass Entry:
In this control we attach a BindableProperty IsExpectedToFocusProperty which we used it to judge whether it is goning to be focused. We also registered a new method OnIsExpectedToFocus to detect propertyChanged for our control. For info about BindableProperty, you could refer to Bindable properties.
MyEntry.cs,
public class MyEntry : Entry
{
public static readonly BindableProperty IsExpectedToFocusProperty = BindableProperty.Create("IsExpectedToFocus", typeof(bool), typeof(MyEntry), false, propertyChanged:OnIsExpectedToFocus);
public bool IsExpectedToFocus
{
get => (bool)GetValue(IsExpectedToFocusProperty);
set => SetValue(IsExpectedToFocusProperty, value);
}
static void OnIsExpectedToFocus(BindableObject bindable, object oldValue, object newValue)
{
// Property changed implementation goes here
if ((bool)newValue == true)
{
(bindable as Entry).Focus();
}
}
}
Step2 Consume custom control in CollectionView. We define the ReturnCommand and its parameter. we will bind them in the MainPageViewModel.
MainPage.xaml,
<CollectionView x:Name="mycoll" ItemsSource="{Binding ItemCollection}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<local:MyEntry x:Name="myentry" Focused="myentry_Focused"
IsExpectedToFocus="{Binding IsExpectedToFocus}"
Text="{Binding Title,Mode=TwoWay}" TextColor="Black"
ReturnCommand="{Binding Source={RelativeSource AncestorType={x:Type local:MainPageViewModel}}, Path=ReturnCommand}"
ReturnCommandParameter="{Binding .}"/>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
In .cs file:
void myentry_Focused(System.Object sender, Microsoft.Maui.Controls.FocusEventArgs e)
{
var entry = sender as Entry;
foreach (var item in viewModel.ItemCollection)
{
if (entry.BindingContext != item)
{
item.IsExpectedToFocus = false;
}
}
}
Step3 Design our MainPageViewModel. I define an ObservableCollection which ItemSource will bind to. And add three items just for test.
Then I think the most important part is to design the Command. Let me explain it briefly. When we press the entry of an Entry, we fire the ReturnCommand and get current Item through ReturnCommandParameter. We get the index of current Item in ItemCollection. So the next entry which needs to be focused corresponds to the index+1 Item. Then we changed the IsExpectedToFocus of the next entry and fire the OnIsExpectedToFocus method which set the entry be focused. Done!
MainPageViewModel.cs
public class MainPageViewModel
{
public ObservableCollection<Item> ItemCollection { get; set; } = new ObservableCollection<Item>();
public Command ReturnCommand
{
get
{
return new Command<Item>((e) =>
{
e.IsExpectedToFocus = false;
int index = ItemCollection.IndexOf(e); // get the current index
if (index != -1)
{
int nextIndex;
// if last entry, next index is 0, else index +1
if (index < (ItemCollection.Count() - 1))
{
nextIndex = index + 1;
ItemCollection[nextIndex].IsExpectedToFocus = true;
}
else if(index == (ItemCollection.Count() - 1))
{
nextIndex = 0;
ItemCollection[nextIndex].IsExpectedToFocus = true;
}
}
});
}
}
public MainPageViewModel()
{
//add three item for test
ItemCollection.Add(
new Item
{
Title = "12345",
IsExpectedToFocus = false
}) ;
ItemCollection.Add(
new Item
{
Title = "23456",
IsExpectedToFocus = false
});
ItemCollection.Add(
new Item
{
Title = "34567",
IsExpectedToFocus = false
});
}
}
Also, this is Item.cs, should implement INotifyPropertyChanged
public class Item : INotifyPropertyChanged
{
public string title;
public bool isExpectedToFocus;
public string Title
{
get
{
return title;
}
set
{
title = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Title)));
}
}
public bool IsExpectedToFocus
{
get
{
return isExpectedToFocus;
}
set
{
isExpectedToFocus = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsExpectedToFocus)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Hope it works for you.
So far I can pass the value to the other view but the problem is I don't know how to do this using MVVM. I tried the documentations and tutorial still no luck. How can I achieve this?
The flow of my project:
- The user will login, when the user provides the correct it will return a JSON array that contains the ContactID of the user.
- This ContactID now be pass to the other view. It will be used to synchronize the server to the local database and vice versa
My Questions are:
1. How can I pass the data to other view with MVVM?
2. How can I check if the data is passed correctly?
The Output of the HTTPWebRequest:
[{"ContactID":"1"}]
My Code:
LoginPageViewModel.cs
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.Data;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TBSMobileApplication.ViewModel
{
public class LoginPageViewModel : INotifyPropertyChanged
{
void OnPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnPropertyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnPropertyChanged(nameof(Password));
}
}
public class LoggedInUser
{
public int ContactID { get; set; }
}
public ICommand LoginCommand { get; set; }
public LoginPageViewModel()
{
LoginCommand = new Command(OnLogin);
}
public void OnLogin()
{
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
MessagingCenter.Send(this, "Login Alert", Username);
}
else
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
var request = HttpWebRequest.Create(string.Format(#link));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
}
else
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var result = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
var contactId = result[0].ContactID;
Application.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(contactId), true);
}
}
}
}
}
else
{
MessagingCenter.Send(this, "Not Connected", Username);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
DatabaseSyncPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace TBSMobileApplication.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class DatabaseSyncPage : ContentPage
{
public DatabaseSyncPage (int contanctId)
{
InitializeComponent ();
}
}
}
If you are new to MVVM i would highly recommend using an MVVM helper framework such as Prism, MVVMCross or MVVMLight (there are even more).
I myself use Prism, I believe all of the frameworks are functionally very similar and it comes down more to preference here. I will show you how I pass data between views in my Prism based applications. Before we get started it would be worth to download the prism visual studio extensions and use the template pack to generate a prism project. I use the DryIoc container.
Imagine the scenario where we have ViewA (with ViewAViewModel) and ViewB (with ViewBViewModel). In View A we have an Entry and a Button, when the button is pressed the text from the entry in ViewA is passed to ViewB where it is displayed in a label.
You would first setup your prism project, creating a XAML fronted view for View A & B and then creating 2 class files and creating the relevant View Models (I'll show you how).
Firstly creating the following files:
ViewA (Xaml content page)
ViewB (Xaml content page)
ViewAViewModel (empty class)
ViewBViewModel (empty class)
In your app.cs register the views and view models:
//You must register these views with prism otherwise your app will crash!
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<ViewA, ViewAViewModel>();
containerRegistry.RegisterForNavigation<ViewB, ViewBViewModel>();
}
Now format your view models by adding the following:
public class ViewAViewModel : ViewModelBase
{
INavigationService _navigationService;
public ViewAViewModel(INavigationService navigationService) : base(navigationService)
{
Title = "ViewA";
_navigationService = navigationService;
}
}
Repeat the above step for ViewBViewModel also (changing the relevant names).
Now in the views xaml lets add some stuff! Add the following to ViewA.xaml (inside <ContentPage.Content></ContentPage.Content>:
<StackLayout>
<Entry Placeholder="Type Here..." Text="{Binding ViewAText}"/>
<Button Text="Navigate" Command="{Binding OnNavigateCommand}"/>
</StackLayout>
and in ViewB.xaml:
`<Label Text="{Binding TextFromViewA}"/>`
Now I've already added the binding for you, so lets make the properties!
In View Model A add:
private string _viewAText;
public string ViewAText
{
get { return _viewAText; }
set { SetProperty(ref _viewAText, value); }
}
public DelegateCommand OnNavigateCommand { get; set; }
private void OnNavigate()
{
//Do Something
}
Now we have a bindable property and a command for our button press, add the following to the constructor:
public ViewAViewModel(INavigationService navigationService) : base(navigationService)
{
Title = "ViewA";
_navigationService = navigationService;
_viewAText = string.Empty;
OnNavigateCommand = new DelegateCommand(OnNavigate);
}
Now View A can bind text from the entry control and has an event handler for the command!
Lets hop into View B and wire that up!
Add the property:
private string _textFromViewA;
public string TextFromViewA
{
get { return _textFromViewA; }
set { SetProperty(ref _textFromViewA, value); }
}
and in the constructor:
public ViewBViewModel(INavigationService navigationService) : base(navigationService)
{
Title = "ViewB";
TextFromViewA = string.Empty;
}
Now the label we added in ViewB is hooked up to the view model. Lets now pass the text from the entry in A to B!
Back in View A add the following to the OnNavigate method:
private void OnNavigate()
{
NavigationParameters navParams = new NavigationParameters();
navParams.Add("PassedValue", _viewAText);
_navigationService.NavigateAsync("ViewB", navParams);
}
The navigation service is incredibly powerful and allows you to pass a dictionary between views (NavigationParameters). In this code we have created some NavigationParameter, added the value of the text in our entry to them and then asked the navigationService (which handles all navigation from viewmodels in Prism) to navigate to ViewB, passing the parameters to it.
In View B we can listen for these parameters using some built in methods provided by Prism. If you type override in ViewBViewModel you will see the methods:
OnNavigatingTo
OnNavigatedTo
OnNavigatedFrom
In this case we want to use OnNavigatingTo (which is fired during the transition between the views). Pull that method in and the following:
public override void OnNavigatingTo(NavigationParameters parameters)
{
base.OnNavigatingTo(parameters);
if (parameters.ContainsKey("PassedValue"))
{
_textFromViewA = (string)parameters["PassedValue"];
RaisePropertyChanged("TextFromViewA");
}
}
Here we check if the parameters contain the value we added (by searching for the dictionary key) and then retrieve the value (casting it to a string since the dictionary is ). We then set the property the label is bound to = to the passed value and then use a prism method, RaisePropertyChanged() to raise a property changed event so that the label's binded value updates!
Below is a gif of the results!
This might be alot to take in. I would advise you start using an MVVM framework asap, they are really easy to use and I would consider them essential to making testable, decoupled MVVM xamarin apps!
For more on how prism works, I'd suggest to go read the docs and watch Brian Lagunas' appearance on the Xamarin Show!
Good Luck!
i had implemented the same and hope this helps you.
i have create a loginViewModel
public class LoginVerificationVM : BaseViewModel // INotifyPropertyChanged
{
private INavigation _navigation;
private string usermobileno;
public string UserMobileNo
{ get { return usermobileno; }set { usermobileno = value;
OnPropertyChanged("UserMobileNo"); }
}
public LoginVerificationVM(INavigation navigation, string mobileno)
{
UserMobileNo = mobileno;
_navigation = navigation;
}
public Command Login
{
get
{
return new Command(async () =>
{
bool status = await WebApi.CheckNetWorkStatus();
if (status == false)
{
MessageClass.messagesWindow("Check Ur Connectivity");
this.Isvisible = false;
return;
}
Isvisible = true;
UserAuth ud = new UserAuth();
ud.username = UserMobileNo; // UserMobileNo;
ud.password = Password; // Password
ud.grant_type = "password"; //GrantType
Isvisible = true;
// IsBusy = false;
await Task.Delay(100);
var json = Task.Run(() => WebApi.GetUserAuth(ud)).Result;
// IsBusy = false;
if (json.ErrorMessage == "true")
{
Application.Current.MainPage = new MasterPages.MasterPage(json.access_token); //or use _navigation.PushAsync(new ForgotPasswordOTP(UserMobileNo));
}
else
{
MessageClass.messagesWindow(json.ErrorMessage);
}
Isvisible = false;
});
}
}
}
Xaml Code
<Entry x:Name="PasswordEntry" Grid.Row="2" IsPassword="True" Placeholder="******" HorizontalTextAlignment="Center" FontAttributes="Bold" TextColor="Black" WidthRequest="150" HeightRequest="35" FontSize="13" Text="{Binding Password, Mode=TwoWay}" >
<Button x:Name="Login" Grid.Row="3" HorizontalOptions="Center" BorderRadius="8" Text="Login" WidthRequest="100" BackgroundColor="#f7941d" TextColor="White" Command="{Binding Login}" IsEnabled="{Binding Active,Mode=TwoWay}">
here is implementation to get data on navigated page view model
public ForgotPasswordOTP(string Ph)
{
InitializeComponent();
BindingContext = new ForgotPasswordOTPViewModel(this.Navigation,Ph);
}
and the last thing you need to do is bind your view with your viewmodel
** BindingContext = new LoginVerificationVM(this.Navigation);**
And the answer for the last question is you need to deserialize json in c#
which can be done in following way
var userData = JsonConvert.DeserializeObject<YourObject>(result);
On a page where I am displaying a receipt to a user, I have a section which lists the subtotal, any taxes, and the total. Since the taxes applicable vary by region and based on the products being sold, the number of rows in this section will vary. For example, here are 3 separate orders, one with GST and PST, one with just GST, and one with neither:
I've accomplished this by putting just the SubTotal in the grid in XAML, and adding the rest in the code-behind in a method I call from the ViewModel. However, I'd really like to avoid doing it this way, so I'm wondering if there is an approach to accomplishing this which doesn't require having the ViewModel know about the View.
A ListView is not suitable here for a number of reasons:
These controls are inside of a ScrollView, and having a ListView inside of a ScrollView causes all sorts of weird problems.
I would like to keep the columns as narrow as their widest element. This is possible with a Grid, but a ListView would take up the entire width of its parent no matter what.
I neither need nor want for my rows to be selectable
So is there a way I can do this without the ViewModel knowing about the View and without resorting to using a ListView?
One way to encapsulate the functionality you require so that the view and the view model are not coupled is by creating a user control.
I created a new user control called TotalsGridControl. Here is the XAML
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScratchPad.UserControls.TotalsGridControl"
x:Name="TotalsGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
And here is the code behind.
public partial class TotalsGridControl : Grid
{
public TotalsGridControl()
{
InitializeComponent();
}
public static readonly BindableProperty TotalsProperty =
BindableProperty.Create(nameof(Totals), typeof(List<TotalItem>), typeof(TotalsGridControl), null,
BindingMode.OneWay, null, OnTotalsChanged);
private static void OnTotalsChanged(BindableObject bindable, object oldvalue, object newvalue)
{
var control = (TotalsGridControl)bindable;
if (control != null)
{
if (newvalue is List<TotalItem> totals)
{
var rowNumber = -1;
double grandTotal = 0;
foreach (var totalItem in totals)
{
grandTotal += totalItem.Value;
var descLabel = new Label {Text = totalItem.Description};
var valueLabel = new Label { Text = totalItem.Value.ToString("c") };
rowNumber++;
control.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto});
control.Children.Add(descLabel, 0, rowNumber);
control.Children.Add(valueLabel, 1, rowNumber);
}
var grandTotalDescLabel = new Label { Text = "Total" };
var grandTotalValueLabel = new Label { Text = grandTotal.ToString("c") };
rowNumber++;
control.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
control.Children.Add(grandTotalDescLabel, 0, rowNumber);
control.Children.Add(grandTotalValueLabel, 1, rowNumber);
}
}
}
public List<TotalItem> Totals
{
get => (List<TotalItem>)GetValue(TotalsProperty);
set => SetValue(TotalsProperty, value);
}
}
I used a bindable property to allow a list of TotalItem to be bound to the user control.
Here is the data in the view model
public List<TotalItem> Totals { get; set; }
Totals = new List<TotalItem>
{
new TotalItem {Description = "SubTotal", Value = 99.91},
new TotalItem {Description = "GST", Value = 5.0},
new TotalItem {Description = "PST", Value = 4.9}
};
and here is the XAML in the page
<userControls:TotalsGridControl Totals="{Binding Totals}"/>
And the output
Before:
public class ReceiptPageModel : PageModelBase
{
private Receipt _receipt;
public Receipt Receipt
{
get => _receipt;
private set => Set(ref _receipt, value);
}
public override void Init(object initData)
{
Receipt = (Receipt) initData;
((ReceiptPage) CurrentPage).AddTaxes(Receipt);
}
}
After:
public class ReceiptPageModel : PageModelBase
{
private Receipt _receipt;
public Receipt Receipt
{
get => _receipt;
private set => Set(ref _receipt, value);
}
public override void Init(object initData)
{
Receipt = (Receipt) initData;
}
}
public partial class ReceiptPage : FreshBaseContentPage
{
public ReceiptPage()
{
InitializeComponent();
BindingContextChanged += HandlePageModelAdded;
}
private void HandlePageModelAdded(object sender, EventArgs e)
{
var pageModel = (ReceiptPageModel)BindingContext;
if (pageModel.Receipt != null)
{
AddTaxes(pageModel.Receipt);
}
else
{
pageModel.PropertyChanged += (s, args) =>
{
if (args.PropertyName == nameof(pageModel.Receipt))
AddTaxes(pageModel.Receipt);
};
}
}
private void AddTaxes(Receipt receipt)
{
...
}
}
I have a combobox displaying the lists within it perfectly in the ViewModel but I'm looking to have it so that when a selected item from the list is chosen it fires the ViewModel screen and I only want one from the list to do this?
So here is what I have in the ChooseView:
<ComboBox x:Name="CatalogName1" SelectedItem="{Binding SelectedCatalog1}" Style="{DynamicResource appComboBox}" Grid.Row="1" Grid.Column="1" >
</ComboBox>
and in the ChooseViewModel:
public List<string> CatalogName1
{
get
{
return new List<string> { "New", "Replace", "Extended", "Nothing", "ShowScreen" };
}
}
private string selectedCatalog1;
public string SelectedCatalog1
{
get
{
return this.selectedCatalog1;
}
set
{
this.selectedCatalog1 = value;
this.NotifyOfPropertyChange(() => this.SelectedCatalog1);
}
}
the "ShowScreen" in the combo list should display the ShowScreenViewModel but I have tried with the getter setter and it's not making sense to me
Okay, this is the way I would fix the problem...
private string selectedCatalog1;
public string SelectedCatalog1
{
get
{
return selectedCatalog1;
}
set
{
selectedCatalog1 = value;
ValidateValue(value);
NotifyOfPropertyChange(() => SelectedCatalog1);
}
}
private void ValidateValue(string s)
{
if (s == "ShowScreen")
{
ActivateItem(new ShowScreenViewModel());
}
}
So I have a radio button that I want to change from being unchecked to being checked based on if a button is clicked. So
the XAML code I have is:
<RadioButton GroupName="rdoExchange" Grid.Row="2" Grid.Column="0" x:Name="PauseRadioButton" Command="{Binding PauseCommand}" IsChecked="{Binding Path=check, Mode=TwoWay}" Margin="3"/>
And the View Model Code:
public string check = "True";
public void Reset(object obj)
{
check = "True";
}
private ICommand m_PauseCommand;
public ICommand PauseCommand
{
get
{
return m_PauseCommand;
}
set
{
m_PauseCommand = value;
}
}
private ICommand m_ResetCommand;
public ICommand ResetCommand
{
get
{
return m_ResetCommand;
}
set
{
m_ResetCommand = value;
}
}
private void SetProperty<T>(ref T field, T value, [CallerMemberName] string name = "")
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
}
I've left out the relaycommand code and several other parts that I feel would be irrelevant to solving the problem.
Would something like this work?
XAML:
<RadioButton GroupName="rdoExchange" IsChecked="{Binding Path=OptionOneChecked, Mode=TwoWay}"/>
<Button Command="{Binding ToggleOptionOne}" Height="20" />
View Model:
public class ViewModel: NotificationObject
{
private bool _optionOneChecked;
public bool OptionOneChecked
{
get { return _optionOneChecked; }
set
{
if (value.Equals(_optionOneChecked)) return;
_optionOneChecked = value;
RaisePropertyChanged("OptionOneChecked");
}
}
public ICommand ToggleOptionOne
{
get { return new DelegateCommand(() => OptionOneChecked = !OptionOneChecked); }
}
}
using the NotificationObject class from the PRISM NuGet package.