While the data is loading, I want to hide the content of the WPF control (which is all contained in a grid) and display a loading trobber.
MainWindow.xaml:
<Grid Visibility="{Binding IsContentVisible}">
<!-- MyCustomView is hosted here -->
</Grid>
The data context of MainWindow is MainWindowViewModel, which also derives from ViewModelBase
public class MainWindowViewModel : ViewModelBase
{}
MyCustomView.xaml:
<Grid>
<TextBox Text="{Binding Data}" />
<TextBlock>This shouldn't be visible during the 2.5 sec loading time, but it is!</TextBlock>
</Grid>
MyCustomViewModel.cs:
public class MyCustomViewModel : ViewModelBase
{
public async void LoadData()
{
IsContentVisible = Visibility.Hidden;
OnPropertyChanged("IsContentVisible");
// Display loading.gif
Data = await repository.LoadData();
// Hide loading.gif
IsContentVisible = Visibility.Visible;
OnPropertyChanged("IsContentVisible");
}
}
ViewModelBase.cs:
public class ViewModelBase : INotifyPropertyChanged
{
private Visbility isContentVisible = Visibility.Visible;
public Visbility IsContentVisible
{
get { return isContentVisible; }
set { isContentVisible = value; }
}
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
private ViewModelBase currentViewModel;
public ViewModelBase CurrentViewModel
{
get { return currentViewModel; }
set { SetProperty(ref currentViewModel, value); }
}
}
and repository.LoadData():
Thread.Sleep(2500);
return "some text";
LoadData() is called as a command of a button
What am I doing wrong? If bind visiblity to the grid of the MyCustomView it works, but that's not the solution, since I'd have many views, and I only want to have binding in one place, the MainWindow.
Have you tried this?
private Visbility isContentVisible = Visibility.Visible;
public Visbility IsContentVisible
{
get { return isContentVisible; }
set
{
isContentVisible = value;
OnPropertyChanged("IsContentVisible");
}
}
Related
In my view, I have a ListBox with some templated items that contain buttons.
<ListBox x:Name="MyListBox" ItemTemplate="{DynamicResource DataTemplate1}"
ItemsSource="{Binding MyItems}">
</ListBox>
And the template for generated items:
<DataTemplate x:Key="DataTemplate1">
<StackPanel Orientation="Horizontal">
<Button Width="50" Click="Button_Click" />
</StackPanel>
</DataTemplate>
When user clicks a button on one of those ListBox items, I want to send the index of that ListBox item to my ViewModel.
So figured to use Binding as it seems to be the way in MVVM. But I'm struggling to set up a binding in code between two properties.
My View code is as follows:
public partial class ItemView : UserControl
{
ViewModel.ItemViewModel VM;
public ItemView()
{
InitializeComponent();
VM = new ViewModel.ItemViewModel();
this.DataContext = VM;
}
private int clickedItemIndex;
public int ClickedItemIndex { get => clickedItemIndex; set => clickedItemIndex = value; }
private void Button_Click(object sender, RoutedEventArgs e)
{
var ClickedItem = (sender as FrameworkElement).DataContext;
ClickedItemIndex = MyListBox.Items.IndexOf(ClickedItem);
}
}
I get the index and set it to ClickedItemIndex property,
I also have property in my ViewModel:
public int SomeInt { get; set; }
Now how do I set up a binding between these two properties?
I'm quite new to MVVM and still learning it. So, maybe this not the correct approach. But I need to have a way for each individual listbox item to be able to call upon an effect in more global viewmodel. For example, if I wanted to have a "Remove" button on each of the listbox items, I would somehow need to send the index to the viewmodel and call the removeItem method with index as the parameter. Or is there a better way to do similar things?
I have a sample app created just for this scenario. I know it seems a lot of code at first glance. Copy this code in your project, that will help debug and get a hang of it(MVVM, databinding, commands and so on).
usercontrol.xaml
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.Resources>
<DataTemplate DataType="{x:Type local:Model}">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=Name}"/>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.UpdateCommand}"
CommandParameter="{Binding}"
Content="Update"/>
<Button Command="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.RemoveCommand}"
CommandParameter="{Binding}"
Content="Remove"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox ItemsSource="{Binding Models}">
</ListBox>
</Grid>
usercontrol.cs
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
DataContext = new ViewModel();
}
}
View model
public class ViewModel : INotifyPropertyChanged
{
private Models _Models;
public Models Models
{
get { return _Models; }
set { _Models = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Models)));
}
}
public ViewModel()
{
Models = new Models();
UpdateCommand = new Command(o => true, UpdateItem);
RemoveCommand = new Command(o => true, RemoveItem);
}
void RemoveItem(object item)
{
Model m = (item as Model);
Models.Remove(m);
}
void UpdateItem(object item)
{
Model m = (item as Model);
m.Name = m.Name + " updated";
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
public ICommand UpdateCommand { get; private set; }
public ICommand RemoveCommand { get; private set; }
}
Icommand implementation
public class Command : ICommand
{
private readonly Func<object, bool> _canExe;
private readonly Action<object> _exe;
public Command(Func<object,bool> canExecute,Action<object> execute)
{
_canExe = canExecute;
_exe = execute;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public bool CanExecute(object parameter)
{
return _canExe(parameter);
}
public void Execute(object parameter)
{
_exe(parameter);
}
}
Model and a collection of models
public class Models : ObservableCollection<Model>
{
public Models()
{
Add(new Model ());
Add(new Model ());
Add(new Model ());
Add(new Model ());
}
}
public class Model : INotifyPropertyChanged
{
static int count = 0;
public Model()
{
Name = "Model "+ ++count;
}
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value;
PropertyChanged(this, new PropertyChangedEventArgs(nameof(Name)));
}
}
public event PropertyChangedEventHandler PropertyChanged = delegate { };
}
You don't need to use a Button in order to select the item. When you click/tap on the item it will get automatically selected.
Then simply bind ListBox.SelectedIndex to your view model property SomeInt and it will update on every selection.
Data binding overview in WPF
You can also get the item itself by binding ListBox.SelectedItem to your view model.
You can handle new values by invoking a handler from the property's set method:
ViewModel.cs
class ViewModel : INotifyPropertyChanged
{
private int currentItemIndex;
public int CurrentItemIndex
{
get => this.currentItemIndex;
set
{
this.currentItemIndex = value;
OnPropertyChanged();
// Handle property changes
OnCurrentItemIndexChanged();
}
}
private MyItem currentItem;
public MyItem CurrentItem
{
get => this.currentItem;
set
{
this.currentItem = value;
OnPropertyChanged();
}
}
protected virtual void OnCurrentItemIndexChanged()
{
// Handle the new this.CurrentItemIndex value
}
// Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
ItemView .xaml
<UserControl>
<UserControl.DataContext>
<ViewModel />
</UserControl.DataContext>
<ListBox ItemsSource="{Binding MyItems}"
SelectedIndex="{Binding CurrentItemIndex}"
SelectedItem="{Binding CurrentItem}" />
</UserControl>
Is there a proper way to create a C#/WPF ViewModel containing subViewModel ?
Objective is:
I have a MainWindow. That window is use to read/create images. There is a button on that windows who switch between 2 UserControl one with IHM used to read image, the other one used to create.
The MainWindow has a MainWindowViewModel with :
command switch
image length
application parameters
I want that both UserControls can acces to MainWindowViewModel field/properties and have they own commands.
Construction will be something like this:
public partial class ReadUserControl : UserControl
{
public ReadUserControl()
{
InitializeComponent();
DataContext = MainViewModel.ReadViewModel;
}
}
public partial class CreateUserControl : UserControl
{
public CreateUserControl()
{
InitializeComponent();
DataContext = MainViewModel.CreateViewModel;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = MainViewModel;
}
}
For example, if a MainViewModel contain a field ImageWidth setting ImageWidth in CreateUserControl change the value for ReadUserControl.
I hope to have been clear, I don't know how design my MainViewModel to achieve this result
EDIT1:
I've created the MainWindowViewModel as a Singleton but i'm still unable to get MainViewModel.CreateViewModel and MainViewModel.ReadViewModel
public class MainWindowViewModel : ViewModelBase
{
private static MainWindowViewModel _instance = null;
public static MainWindowViewModel Instance
{
get
{
if (_instance == null)
_instance = new MainWindowViewModel();
return _instance;
}
}
private MainWindowViewModel()
: base()
{
}
#region CreateViewModel
/* How to create ? */
#endregion
#region ReadViewModel
/* How to create ? */
#endregion
}
Your example will work. At least if you have made your MainViewModel a Singleton.
A more professional approach might be an Constructor-Injection like this.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(MainViewModel vm)
{
InitializeComponent();
DataContext = vm.ReadViewModel;
}
}
With such DependencyInjections you can achieve a higher level of abstraction, since your UserControls can be generalized. (They will all have the same Constructor)
On the other hand, you give every such UserControl the ability, to manipulate the MainViewModel, not aware of side-effects.
In your special case, it would be more safe, to pass only the needed parameters to the UserControl, instead of giving them a bunch of informations, they will never need.
public partial class ReadUserControl : UserControl
{
public ReadUserControl(Icommand command, int imageLength, AppParams appParams)
{
InitializeComponent();
...
// Do with your Constructorparameters what ever you have to
}
}
Edit:
Here a small, dumb implementation of how it could be done:
Code
public class MainViewModel : INotifyPropertyChanged {
private INotifyPropertyChanged _selectedViewModel;
public MainViewModel() {
var cmd = new RelayCommand(x => {
MessageBox.Show("HelloWorld");
}, x => true);
this.RVM = new ReadViewModel(cmd);
this.WVM = new WriteViewModel(cmd);
this.SelectedViewModel = WVM;
}
private ICommand _switchViewModelCommand;
public ICommand SwitchViewModelCommand => this._switchViewModelCommand ?? (this._switchViewModelCommand = new RelayCommand(x => {
if (this.SelectedViewModel == RVM) {
this.SelectedViewModel = WVM;
return;
}
this.SelectedViewModel = RVM;
}));
public INotifyPropertyChanged SelectedViewModel {
get {
return this._selectedViewModel;
}
set {
if (Equals(value, this._selectedViewModel))
return;
this._selectedViewModel = value;
this.OnPropertyChanged();
}
}
public ReadViewModel RVM {
get; set;
}
public WriteViewModel WVM {
get; set;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ReadViewModel : INotifyPropertyChanged {
public ReadViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class WriteViewModel : INotifyPropertyChanged {
public WriteViewModel(ICommand sayHelloCommand) {
this.HelloCommand = sayHelloCommand;
}
public ICommand HelloCommand {
get;
}
public ICommand HelloMoonCommand => new RelayCommand(x => { MessageBox.Show("Hello Moon"); });
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
XAML
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<Grid Height="200">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<ContentControl Content="{Binding SelectedViewModel, UpdateSourceTrigger=PropertyChanged}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type local:ReadViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
</StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type local:WriteViewModel}">
<StackPanel>
<Button Content="Say Hello world" Command="{Binding HelloCommand}"></Button>
<Button Content="Say Hello Moon" Command="{Binding HelloMoonCommand}"></Button>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
<Button Content="Switch VM" Command="{Binding SwitchViewModelCommand}" Grid.Row="1"/>
</Grid>
You can pass in the MainViewModel as DataContext for your user control and set the data context of elements as Read/Create model
something like
<Grid> <!--using MainWindowViewModel as data context-->
<Grid DataContext="{Binding Path=CreateViewModel}"> <!--using CreateViewModel as data context-->
.....
</Grid>
<Grid>
I want to create master page in mvvm. I created a viewbox that it's name is container for showing my usercontrols and I have two classes, RelayCommand and ViewModel.
Here is my code:
public class ViewModel
{
MainWindow objMainWindow = new MainWindow();
UserControls.History objHistory = new UserControls.History();
UserControls.NewItem objNewItem = new UserControls.NewItem();
UserControls.SideEffect objSideEffect = new UserControls.SideEffect();
public ViewModel()
{
OpenCommand = new RelayCommand(Open);
}
private ICommand openCommand;
public ICommand OpenCommand
{
get { return openCommand; }
set { openCommand = value; }
}
public void Open(object sender)
{
if (sender.ToString() == "btnHistory")
{
objMainWindow.Container.Child = objHistory;
}
if (sender.ToString() == "btnNewItem")
{
}
if (sender.ToString() == "btnSideEffect")
{
}
}
}
And this is my RelayCommand:
public class RelayCommand:ICommand
{
public RelayCommand(Action<object> _action)
{
actionCommand = _action;
}
private Action<object> actionCommand;
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
if (parameter !=null)
{
actionCommand(parameter);
}
else
{
actionCommand("Null");
}
}
}
but when I run solution I faced with NullRefrenceException when it wanted to show my child of container.
I don't know how to make this work.
Your MainWindow instantiates when your program starts. So you shouldn't instantiate it again in your ViewModel (i.e. this line: MainWindow objMainWindow = new MainWindow();). You should use DataBinding instead.
Here is a sample code that gives you an idea:
First define a property of type FrameworkElement in you ViewModel and set it's value to your desired UserControl in the Open method.
ViewModel:
public class ViewModel : INotifyPropertyChanged
{
FrameworkElement _myUc;
public FrameworkElement MyUserControl
{
get
{
return _myUc;
}
set
{
_myUc= value;
OnPropertyChanged("MyUserControl");
}
}
public ViewModel()
{
OpenCommand = new RelayCommand(Open);
}
public void Open(object sender)
{
if (sender.ToString() == "btnHistory")
{
MyUserControl = objHistory;
}
}
// rest of your view model ...
}
Then instantiate your ViewModel as the DataContext of your MainWindow in the Constructor.
MainWindow:
public ViewModel MyViewModel { get; set; }
public MainWindow()
{
InitializeComponent();
MyViewModel = new ViewModel();
DataContext = MyViewModel;
}
And Finally use a ContentControl (instead of ViewBox) [see my note] and bind it's Content to the MyUserControl property of your ViewModel.
XAML:
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" Content="{Binding MyUserControl}" x:Name="Container"/>
<Button Grid.Row="1" Name="btnHistory" Content="ShowHistory" Command="{Binding OpenCommand}" />
</Grid>
This way each time MyUserControl changes, the ContentControl shows your desired UserControl.
Note that Child property of ViewBox is not a DependencyProperty and thus not bind-able.
So, I have a project with a scrolling text (marqee) that rotates over a string array. And I want it to change the string value after 20 seconds of each animation iteration.
There is a problem though, the property(ScrollingText) that uses the INotifyPropertyChanged interface to bind to a textblock(using XAML) does not return after the first iteration. Even though it refreshes normally(in the set part), it does not return on the Getter part.... except for the first set in the default ctor.
MAIN CLASS:
class GetScrollingText : CommonBase
{
private string _scrollingtext = String.Empty;
DoubleAnimation Animation;
public GetScrollingText()
{
ScrollingText = GetScrollString();
}
public string ScrollingText
{
get
{
return _scrollingtext;
}
set
{
if (value != _scrollingtext)
{
_scrollingtext = value;
RaisePropertyChanged("ScrollingText");
}
}
} // INJECTS the string in the animated textblock {binding}.
public TextBlock scrollBlock { get; set; }
string GetScrollString()
{
.........
return scrolltext;
}
public void LeftToRightMarqee(double from, double to)
{
Animation = new DoubleAnimation();
Animation.From = from;
Animation.To = to;
Animation.Duration = new Duration(TimeSpan.FromSeconds(20));
Animation.Completed += animation_Completed;
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
void animation_Completed(object sender, EventArgs e)
{
ScrollingText = GetScrollString();
scrollBlock.BeginAnimation(Canvas.LeftProperty, Animation);
}
}
For some reason the animation_Completed Event only changes the value ScrollingText, but it does not invoke the Getter part therefore there is not a return to the {binding}.
XAML:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:AnnouncingSys"
x:Class="AnnouncingSys.MainWindow"
x:Name="Window"
Width="1280" Height="720" MinHeight="566" MinWidth="710">
<Window.Resources>
<vm:GetScrollingText x:Key="ScrollingText"/>
</Window.Resources>
<Canvas x:Name="MainCanvas" ClipToBounds="True" Margin="0,0,0,0" Grid.Row="5" Background="Black" Grid.ColumnSpan="5" >
<TextBlock x:Name="ScrollBlock" TextWrapping="Wrap" VerticalAlignment="Top" Height="113" Width="5147" Canvas.Left="-1922" Text="{Binding ScrollingText, Source={StaticResource ScrollingText}}"/>
</Canvas>
</Window>
CODE BEHIND:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
}
}
And finally the helper class CommonBase:
public class CommonBase : INotifyPropertyChanged
{
protected CommonBase()
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string PropertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(PropertyName);
handler(this, e);
}
}
}
I have even put a breakpoint on the return block of the Getter but it only activates on the first: "ScrollingText = GetScrollString()". I mean, shouldn't it return each time the value is changed???
You are using two different instances of your GetScrollingText class, one in XAML as StaticResource, the other in code behind as the scrolling field in class MainWindow.
Instead of creating a StaticResource in XAML, you could just set the DataContext property of your MainWindow:
public partial class MainWindow : Window
{
GetScrollingText scrolling = new GetScrollingText();
public MainWindow()
{
InitializeComponent();
scrolling.scrollBlock = this.ScrollBlock;
scrolling.LeftToRightMarqee(2000, -3000);
DataContext = scrolling; // here
}
}
Now you would not explicitly set the binding's Source property, because the DataContext is used as default binding source:
<TextBlock ... Text="{Binding ScrollingText}"/>
I'm just start working on metro app and i'm facing a problem that is dispatcher not updating the UI. My code is below please let me know what was the issue ?
public class Test : DependencyObject
{
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("NameOfPerson", typeof(string), typeof(Test), null);
public String NameOfPerson
{
get
{
return (string)GetValue(CurrentItemProperty);
}
set
{
runmethod(value);
}
}
public async void runmethod(String text)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
SetValue(CurrentItemProperty, text);
}
);
}
}
In main page i have an event button click which when fire update textbox.
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Test t = new Test();
t.NameOfPerson = "Hello Umar";
}
MainPage.xaml look like this
<Page
x:Class="TestApplication.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestApplication"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Button" HorizontalAlignment="Left" Margin="207,187,0,0" VerticalAlignment="Top" Height="80" Width="255" Click="Button_Click_2"/>
<TextBox x:Name="textB" Text="{Binding NameOfPerson}" HorizontalAlignment="Left" Height="80" Margin="730,187,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="307"/>
</Grid>
</Page>
If you are what you are trying to do is having a button refresh your Text, you should look into the MVVM pattern and have the Binding update your UI.
To do this you'll have to create your Object, in this case, let's say a person.
public class Person
{
public string Name { get; set; }
}
Secondly you would want to have a person inside a viewmodel that you'll update using your button. The viewmodel will derive from BindableBase which is a part of Windows Store applications if you would use such thing as Basic Page. The Viewmodel looks like this:
public class MainPageViewModel : BindableBase
{
public MainPageViewModel()
{
}
private Person person;
public Person Person
{
get { return person; }
set { SetProperty(ref person, value); }
}
public void LoadData()
{
Person = new Person() { Name = "Simple name" };
}
public void UpdatePerson()
{
Person.Name = "Updated Name";
OnPropertyChanged("Person");
}
}
and in case you dont have the bindableBase, it looks like this:
[Windows.Foundation.Metadata.WebHostHidden]
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null)
{
if (object.Equals(storage, value)) return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
On your MainPage you create the ViewModel and set the DataContext on your Page. Also you would want to handle your object inside your Viewmodel, so you'll create a update method when clicking the button that will modify your Person object:
public sealed partial class MainPage : Page
{
private readonly MainPageViewModel viewModel;
public MainPage()
{
this.InitializeComponent();
viewModel = new MainPageViewModel();
viewModel.LoadData();
this.DataContext = viewModel;
}
private void Button_Tapped(object sender, TappedRoutedEventArgs e)
{
viewModel.UpdatePerson();
}
}
And finally your TextBox in the UI to point at the Person's name property inside the Viewmodel:
<TextBox
x:Name="textB"
Text="{Binding Person.Name}"
HorizontalAlignment="Left"
Height="80"
Margin="730,187,0,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Width="307" />
I hope this fulfills your question on how you can have a button updating your UI.