I am having a major problem binding my data from TextBox to ViewModel To TextBlock. I have set up my following Xaml Code like so:
<Page
x:Class="digiBottle.MainPage"
DataContext="{Binding Source=UserProfile}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:digiBottle"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
DataContext="{Binding Source=UserProfile}">
<TextBlock HorizontalAlignment="Left" Margin="219,72,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="32" Width="232" Text="{Binding userFirstName, Mode=OneWay}"/>
<TextBox HorizontalAlignment="Left" Margin="39,72,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="111" Text="{Binding userFirstName, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
The .cs file I am trying to use as a source is defined as follows:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace digiBottle.Model
{
public class UserProfile : INotifyPropertyChanged
{
public int ID { get; set; }
public string userFirstName;
public string userLastName { get; set; }
public int age { get; set; }
public int weight { get; set; }
public int height { get; set; }
public DateTime signupTime { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public UserProfile()
{
userFirstName = "First Name";
}
private void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public UserProfile getCopy()
{
UserProfile copy = (UserProfile)this.MemberwiseClone();
return copy;
}
}
}
What am i doing wrong when trying to bind my TextBox and TextBlock to userFirstName in the UserProfile.cs Source. ANy help would be a major help!
Thank you
The first thing I notice here is that your properties (setter) are not raising event change. You need to call RaisePropertyChanged in your properties setter.
I would have written it like
A private field
private String _userFirstName;
Then in constructor
public UserProfile()
{
this._userFirstName = "First Name";
}
With Property raising event
public String UserFirstName
{
get { return this._userFirstName; }
set
{
this._userFirstName = value;
this.RaisePropertyChanged("UserFirstName");
}
}
And then in XAML, bind it with property "UserFirstName" with two way binding
<TextBlock HorizontalAlignment="Left" Margin="219,72,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="32" Width="232" Text="{Binding UserFirstName, Mode=OneWay}"/>
<TextBox HorizontalAlignment="Left" Margin="39,72,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="111" Text="{Binding UserFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
DataBinding can be hard to understand at first. Please refer to Data binding for Windows Phone 8 to get yourself started.
For your code: Here are the fixes you will need:
Remember you can only bind to a property.
You need to raise the event on the set action.
You may need twoway binding on the textbox depending on the actions you want.
You need to set the DataContext for both textbox and the textblock.
Here are the changes:
CS
public class UserProfile : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
string user_first_name;
public String UserFirstName
{
get { return user_first_name; }
set
{
user_first_name = value;
OnPropertyChanged("UserFirstName");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
UserProfile up = new UserProfile();
this.tb1.DataContext = up;
this.tb2.DataContext = up;
}
}
XAML
<TextBlock x:Name="tb2" TextWrapping="Wrap" Text="{Binding UserFirstName}"/>
<TextBox x:Name="tb1" HorizontalAlignment="Left" Height="72" Margin="14,475,0,0" Grid.Row="1" TextWrapping="Wrap" Text="{Binding UserFirstName, Mode=TwoWay}" VerticalAlignment="Top" Width="456" />
Related
Ok, I tried it several ways, but none worked as it should be in my case. I have a simple Window with a single ComboBox. I am changing the code to MVVM, so now everything is still in the Code-Behind and should go to a ViewModel, etc.
But even on the first step (binding the ViewModel to the View/Window) I don't seem to be able to bind them together.
My Window XAML:
<Window x:Class="CustomerGuidance.ClientWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:VM="clr-namespace:CustomerGuidance.ViewModels"
Title="Stop'n'Go - Client" Height="22" Width="229"
Loaded="ClientWindow_OnLoaded" WindowStyle="None"
WindowStartupLocation="Manual" Top="0" Left="0"
ResizeMode="NoResize" ShowInTaskbar="False" Topmost="True">
<Window.DataContext>
<VM:EmployeeViewModel />
</Window.DataContext>
<Canvas Background="Gainsboro">
<ComboBox Name="EmployeesComboBox"
ItemsSource="{Binding EmployeeEntries}"
Width="192" FontFamily="Arial" FontSize="14">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Lastname}" />
<TextBlock Text=", " />
<TextBlock Text="{Binding Surname}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Canvas>
The ViewModel looks like this:
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace CustomerGuidance.ViewModels
{
public class EmployeeViewModel : INotifyPropertyChanged
{
public EmployeeViewModel()
{
}
public static ObservableCollection<ServerWindow.EmployeeEntry> EmployeeEntries { get; set; } = new ObservableCollection<ServerWindow.EmployeeEntry>();
private string _surname;
private string _lastname;
private int _id;
public string Surname
{
get { return _surname; }
set
{
if (_surname == value)
return;
_surname = value;
NotifyPropertyChanged("Surname");
}
}
public string Lastname
{
get { return _lastname; }
set
{
if (_lastname == value)
return;
_lastname = value;
NotifyPropertyChanged("Lastname");
}
}
public int Id
{
get { return _id; }
set
{
if (_id == value)
return;
_id = value;
NotifyPropertyChanged("Id");
}
}
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
I get the following error message: "The Name "EmployeeViewModel" is not available in the namespace "clr-namespace:CustomerGuidance.ViewModels".And now the question: What am I missing? How can I bind the ViewModel to my window-XAML?
You should build your code for the errors to disappear.
It's because the namespace is not yet available in the assembly the designer relies on (your program) before it has been built.
WPF n00bie here, trying to get his UI to work properly.
So I made this test example. The textblock bound to HeaderText1 changes correctly at the launch of the app, but the textblock bound to HeaderText2 doesn't update after clicking the button.
What am I doing wrong? Thanks in advance!!
<Window x:Class="DataBinding.DataContextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataContextSample" Height="142.596" Width="310">
<StackPanel Margin="15">
<WrapPanel>
<TextBlock Text="Window title: " />
<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
<Button Name="btnUpdateSource" Click="btnUpdateSource_Click" Margin="5,0" Padding="5,0">*</Button>
</WrapPanel>
<TextBlock Text="{Binding Path=DataContext.HeaderText}"></TextBlock>
<TextBlock Text="{Binding Path=DataContext.HeaderText2}"></TextBlock>
</StackPanel>
</Window>
Main window class:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace DataBinding
{
public partial class DataContextSample : Window
{
public string HeaderText { set; get; }
public DataContextSample()
{
HeaderText = "YES";
InitializeComponent();
this.DataContext = this;
}
private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
{
BindingExpression binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
Source source = new Source();
source.HeaderText2 = "YES2";
}
}
}
And the INotifyPropertyChanged class
using System.ComponentModel;
namespace DataBinding
{
public class Source : INotifyPropertyChanged
{
public string HeaderText2 { set; get; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
}
First of all you are doing many things wrong.
You should not be using the window as it's own datacontext, you should have a viewmodel that you set.
You should not be using event handlers in the view to manipulate the viewmodel. You should bind the button to a command.
Your source seems to be a "viewmodel", consider renaming it to MainWindowViewModel (for clarity) and then do this.
public class MainWindowViewModel : INotifyPropertyChanged
{
private string headerText;
private string headerText2;
private ICommand updateHeaderText2;
public string HeaderText
{
set
{
return this.headerText;
}
get
{
this.headerText = value;
// Actually raise the event when property changes
this.OnPropertyChanged("HeaderText");
}
}
public string HeaderText2
{
set
{
return this.headerText2;
}
get
{
this.headerText2 = value;
// Actually raise the event when property changes
this.OnPropertyChanged("HeaderText2");
}
}
public ICommand UpdateHeaderText2
{
get
{
// Google some implementation for ICommand and add the MyCommand class to your solution.
return new MyCommand (() => this.HeaderText2 = "YES2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
And set this viewmodel to the datacontext of your window.
this.DataContext = new MainWindowViewModel();
And then in your xaml you should bind to the viewmodel as such
<Window x:Class="DataBinding.DataContextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataContextSample" Height="142.596" Width="310">
<StackPanel Margin="15">
<WrapPanel>
<TextBlock Text="Window title: " />
<!-- Not sure what this binding is? -->
<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
<Button Name="btnUpdateSource" Command="{Binding UpdateHeaderText2}" Margin="5,0" Padding="5,0">*</Button>
</WrapPanel>
<TextBlock Text="{Binding HeaderText}"></TextBlock>
<TextBlock Text="{Binding HeaderText2}"></TextBlock>
</StackPanel>
</Window>
You set the DataContext to this (the window). You don't have a property named HeaderText2 in the DataContext so the second binding won't work.
I'd do this (without changing your code too much, in reality I'd do a proper MVVM approach):
public partial class DataContextSample : Window
{
public Source Source { get; set; }
public string HeaderText { set; get; }
public MainWindow()
{
InitializeComponent();
HeaderText = "YES";
Source = new Source { HeaderText2 = "YES" };
DataContext = this;
}
private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
{
BindingExpression binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
if (binding != null)
{
binding.UpdateSource();
}
Source.HeaderText2 = "YES2";
}
}
I added a new property called Source which is of type Source. Set its initial HeaderText2 to the same "YES" in the constructor and in the button click change that to "YES2".
You have to change your Source class as well, to actually notify about changes:
public class Source : INotifyPropertyChanged
{
private string _headerText2;
public string HeaderText2
{
get { return _headerText2; }
set
{
_headerText2 = value;
OnPropertyChanged("HeaderText2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
}
And then in your XAML:
<StackPanel Margin="15">
<WrapPanel>
<TextBlock Text="Window title: " />
<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
<Button Name="btnUpdateSource" Click="btnUpdateSource_Click" Margin="5,0" Padding="5,0">*</Button>
</WrapPanel>
<TextBlock Text="{Binding Path=HeaderText}"></TextBlock>
<TextBlock Text="{Binding Path=Source.HeaderText2}"></TextBlock>
</StackPanel>
Well there are a few issues with your code.
First of all, you never assign your "Source" to a datacontext, so there's no way for your second TextBlock to find the value of "HeaderText2".
If however you would assign your "Source" to the textblocks datacontext then we could fetch the value of "HeaderText2". Consider the code below
<Window x:Class="DataBinding.DataContextSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataContextSample" Height="142.596" Width="310">
<StackPanel Margin="15">
<WrapPanel>
<TextBlock Text="Window title: " />
<TextBox Name="txtWindowTitle" Text="{Binding Title, UpdateSourceTrigger=Explicit}" Width="150" />
<Button Name="btnUpdateSource" Click="btnUpdateSource_Click" Margin="5,0" Padding="5,0">*</Button>
</WrapPanel>
<TextBlock Text="{Binding Path=HeaderText}"></TextBlock>
<TextBlock Name="TextBlock2" Text="{Binding Path=HeaderText2}"></TextBlock>
</StackPanel>
</Window>
We have given your second Textblock a name, "TextBlock2" and also removed the "Datacontext"-part from your binding.
Then we have moved the Creation of your "Source" object from the button event to the windows constructor (there is no need to make a new one everytime we click a button when all we want to do is to update a property)
public partial class DataContextSample : Window
{
public string HeaderText { set; get; }
private Source source { get; set; }
public DataContextSample()
{
...
source = new Source();
TextBlock2.DataContext = source;
...
}
...
}
And then in your buttons click-event we assign your databound property a value of "YES2".
private void btnUpdateSource_Click(object sender, RoutedEventArgs e)
{
...
source.HeaderText2 = "YES2";
}
There is however one more detail. Your class "Source" does implement "INotifyPropertyChanged", but it never "uses" it. By that I mean, that when you assign a value to your property "HeaderText2" you never actually "notify" the UI that something has changed with it, and thus the UI will not fetch the new value. Consider the code below:
public class Source : INotifyPropertyChanged
{
public string HeaderText2 { set
{
headerText2 = value;
OnPropertyChanged("HeaderText2");
}
get
{
return headerText2;
}
}
string headerText2;
...
}
So let's take a look at what we've done with the property "HeaderText2". Everytime the "HeaderText2" gets a value assigned, it will first save the value in a privat property (so that we can read from it later). But in addition to that we also call the "OnPropertyChanged" method with our Propertys name. That method will in turn check if anyone is "listening" to our "PropertyChanged"-event (and since we have a databinding on the current object, someone is listening), and create a new event.
Now we have assigned a datasource to your textblock with a path to "HeaderText2", we are notifying all listeners when we update "HeaderText2" on the datasource and we are updating "HeaderText2" on the buttons click event.
Happy coding!
My first try at C#, WPF, and MVVM. I've looked at several answers and tutorials and just cannot seem to get this right.
I have a View a Model and a ViewModel file (Actually more, but trying to simplify). In the view I want to bind a textbox to a view model member. I also want to bind a button click to a view model method.
The delegate command for Login() works fine, but I can't seem to update the ID property in Acc.ID.
What would I need to change to be able to do both?
I understand I will probably need to implement the PropertyChanged event in the ViewModel instead of the Model...I just don't understand how.
What I can do is set the DataContextto user.Acc in the code behind to directly update the model, but then I obviously cannot bind to the Login() method.
ViewModel.cs
public class LoginVM
{
private ServerInterface _serverInterface;
private ICommand _loginCommand;
private EmployeeAccount _acc;
public ICommand LoginCommand
{
get { return _loginCommand; }
}
public LoginVM()
{
Acc = new EmployeeAccount();
_serverInterface = new ServerInterface();
_loginCommand = new DelegateCommand<String>(Login);
}
public EmployeeAccount Acc { get; set; }
private void Login(object state)
{
this.Acc.ID = _serverInterface.Encrypt(this.Acc.ID);
}
}
View.xaml.cs
public partial class LoginView : Window
{
public LoginView()
{
InitializeComponent();
BindInXaml();
}
private void BindInXaml()
{
base.DataContext = new LoginVM();
}
}
Model.cs
public class EmployeeAccount : INotifyPropertyChanged
{
String _id;
public EmployeeAccount()
{
ID = "5000";
Name = "George Washington";
isAdmin = true;
Pswd = "TheyDont";
}
public String ID
{
get { return _id; }
set
{
_id = value;
this.OnPropertyChanged("ID");
}
}
public string Name { get; set; }
public Boolean isAdmin { get; set; }
public string Pswd { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(
this, new PropertyChangedEventArgs(propName));
}
}
.xaml Put in only what matters really
<TextBox x:Name="txtLogInName" Margin="60,43,42,129" TextWrapping="Wrap" Text="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}" Width="120" Grid.Column="1" Grid.Row="1"/>
<Button x:Name="btnLogIn" Content="Log on" Command="{Binding LoginCommand}" Margin="160,151,10,23" Grid.Column="1" Grid.Row="1" RenderTransformOrigin="1.667,0.545"/>
<TextBlock x:Name="txtBlockPassReset" TextAlignment="Center" Grid.Row="1" Grid.Column="1" RenderTransformOrigin="1.348,1.765" Margin="60,101,42,78">
<Hyperlink>Reset Password</Hyperlink>
</TextBlock>
<PasswordBox x:Name="pswdBoxLoginPass" Grid.Column="1" HorizontalAlignment="Left" Margin="60,72,0,0" Grid.Row="1" VerticalAlignment="Top" Width="120" Password="Password"/>
Try changing your xaml from
<TextBox x:Name="txtLogInName" Margin="60,43,42,129" TextWrapping="Wrap"
Text="{Binding Path=ID, UpdateSourceTrigger=PropertyChanged}"
Width="120" Grid.Column="1" Grid.Row="1"/>
to
<TextBox x:Name="txtLogInName" Margin="60,43,42,129" TextWrapping="Wrap"
Text="{Binding Path=Acc.ID, UpdateSourceTrigger=PropertyChanged}"
Width="120" Grid.Column="1" Grid.Row="1" />
I have a ListBox created by ItemTemplate and Binding
<controls:PanoramaItem Header="{Binding AppResources.SettingsSubpage2, Source={StaticResource LocalizedStrings}}" HeaderTemplate="{StaticResource HeaderTemplate}">
<Grid>
<ListBox x:Name="DayOfWeekSelector" ItemTemplate="{StaticResource DayOfWeekTemplate}" ItemsSource="{Binding DayOfWeekElementList}" Foreground="{StaticResource AppForegroundColor}" LostFocus="DayOfWeekSelector_LostFocus" HorizontalAlignment="Left" Width="420" />
</Grid>
</controls:PanoramaItem>
Template code:
<phone:PhoneApplicationPage.Resources>
<!--- ... --->
<DataTemplate x:Key="DayOfWeekTemplate">
<Grid Height="65" Width="332">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<CheckBox IsChecked="{Binding IsActive, Mode=TwoWay}" Tag="{Binding}" d:LayoutOverrides="Width, Height" BorderBrush="{StaticResource AppBackgroundColor}" Background="{StaticResource ScheduleBackgroundAccentsColor}" Grid.Column="0" Unchecked="CheckBox_Unchecked" />
<StackPanel Grid.Column="1" Orientation="Horizontal">
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" d:LayoutOverrides="Width"/>
<TextBlock Text="{Binding TaskCounter, Mode=OneWay, Converter={StaticResource DayOfWeekCounter}}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
</DataTemplate>
<!--- ... --->
And it's working fine. I've got all my items on the list. Checkboxes are binded to appropriate elements (clicking on it is changing proper value).
But by default ListBox can be also selected. Selection high-light TextBox binded to Name but don't change CheckBox (binded to IsActive). How can I tie item selection changing to checkbox state changing (in Silverlight)?
Edit:
public partial class SettingsPage : PhoneApplicationPage, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public List<DayOfWeekElement> DayOfWeekList
{
get
{
return CyberSyncPlanBase.Instance.DayOfWeekElementList;
}
set
{
CyberSyncPlanBase.Instance.DayOfWeekElementList = value;
NotifyPropertyChanged("DayOfWeekList");
}
}
public SettingsPage()
{
InitializeComponent();
DayOfWeekSelector.DataContext = CyberSyncPlanBase.Instance;
}
private void DayOfWeekSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DayOfWeekElement dowe = (DayOfWeekElement) DayOfWeekSelector.SelectedItem;
if (dowe != null)
dowe.IsActive = (dowe.IsActive) ? false : true;
}
And in singleton INotifyPropertyChanged i've implemented in the same way:
private List<DayOfWeekElement> dayOfWeekElementList;
public List<DayOfWeekElement> DayOfWeekElementList
{
get { return dayOfWeekElementList; }
set
{
dayOfWeekElementList = value;
RecalcWeekTasks();
NotifyPropertyChanged("DayOfWeekElementList");
}
}
Bottom class:
public class DayOfWeekElement
{
public string Name { get { return this.DayOfWeek.ToStringValue(); } }
public bool IsNotEmpty { get { return (TaskCounter > 0); } }
public int TaskCounter { get; set; }
public bool IsActive { get; set; }
public DayOfWeek DayOfWeek { get; set; }
}
I think you could use the SelectedItem property of the ListBox control.
A possible implementation could be this:
Subscribe to the event SelectedIndexChanged of the ListBox.
Get the selected item.
For the selected item, change its IsActive property to true.
This works if the interface INotifyPropertyChanged is implemented in your data class.
E.g.:
public class DayOfWeekElement : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private bool isActive = false;
public bool IsActive {
get
{
return this.isActive;
}
set
{
if (value != this.isActive)
{
this.isActive= value;
NotifyPropertyChanged("IsActive");
}
}
}
}
I am trying to post some values to the next screen through XML serialization and Isolated Storage. Values are posted from textbox and also from textBlock to the next screen's textBlocks with button click event. But the TextBlock's text is not posted to the next screen, only the textBox text is posted. If I debug and check, XML shows as "" with no string loadedinto it. It's also not binding as well. Why?
//MainPage.xaml
<StackPanel>
<Button Margin="10"
Content="Simple Sample"
Name="btnSimple"
Click="btnSimple_Click">
</Button>
<TextBlock TextWrapping="Wrap" Text="{Binding FirstName, Mode=TwoWay}"/>
<TextBlock TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}"/>
</StackPanel>
//MainPage.xaml.cs
using System;
using System.Windows;
using Microsoft.Phone.Controls;
using System.IO;
using System.IO.IsolatedStorage;
using System.Text;
using System.Xml.Serialization;
namespace WPIsolatedStorage
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
private LastUser _User = new LastUser();
private const string USER_KEY = "LastUser";
public MainPage()
{
InitializeComponent();
}
private void GetUser()
{
string xml;
xml = IsolatedStorageSettings.ApplicationSettings[USER_KEY].ToString();
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(xml)))
{
XmlSerializer serializer = new XmlSerializer(typeof(LastUser));
_User = (LastUser)serializer.Deserialize(ms);
}
}
private void btnSimple_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Uri("/PageSimple.xaml", UriKind.Relative));
}
private void PhoneApplicationPage_Loaded_1(object sender, RoutedEventArgs e)
{
if (IsolatedStorageSettings.ApplicationSettings.Contains(USER_KEY))
GetUser();
this.DataContext = _User;
}
}
}
//LastUser.cs
using System.ComponentModel;
namespace WPIsolatedStorage
{
public class LastUser : INotifyPropertyChanged
{
#region INotifyPropertyChanged Event
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region Private Variables
private string mFirstName = string.Empty;
private string mTextBlock = string.Empty;
#endregion
#region Public Variables
public string FirstName
{
get { return mFirstName; }
set
{
if (mFirstName != value)
{
mFirstName = value;
RaisePropertyChanged("FirstName");
}
}
}
public string MyText
{
get { return this.mTextBlock; }
set
{
this.mTextBlock = value;
this.RaisePropertyChanged("MyText");
}
}}
}
//SeconPage.xaml
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding FirstName, Mode=TwoWay}"
Name="txtFirstName" />
<TextBlock Grid.Column="1" Name="MyTextBlock" HorizontalAlignment="Left" Margin="12,178,0,-224" Grid.Row="4" TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}" VerticalAlignment="Top" Height="93" Width="191" FontSize="36"/>
There is a typo in you binding expression. Should be
<TextBlock Grid.Column="1" .... Text="{Binding MyText}" ../>
instead of
<TextBlock Grid.Column="1" .... Text="{Binding Mytext}" ../>
My second assumption is: you use a simple binding in your code
<TextBlock TextWrapping="Wrap" Text="{Binding MyText, Mode=TwoWay}"/>
But in Windows Phone the binding works only after you unfocused control. You can find a discussion and few solutions here:
TextBox Binding TwoWay Doesn't Update Until Focus Lost WP7
Try This.
Code snippet[C#]:
public class Data : INotifyPropertyChanged
{
private int customerID;
public int CustomerID
{
get { return customerID; }
set { customerID = value; OnPropertyChanged("CustomerID"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
Code snippet[XAML]:
<TextBlock Content="{Binding CustomerID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"