binding property of one field to another in wp7 - windows-phone-7

<TextBlock Name="currency" TextWrapping="Wrap" VerticalAlignment="Center"/>
<TextBlock Margin="5,0" Text="{Binding Text, ElementName=currency" TextWrapping="Wrap" VerticalAlignment="Center" FontSize="22" />
I am using the above code for binding property of one field to another in my WP7 application.
i want to do the similar task from back-end. any suggestions??

Bindings are working in a specified data context. You can set the data context of your layout root to the page instance, then you can bind to any of your properties. (DataContext is inherited through the child FrameworkElements.) If you want your binding to update its value whenever you change your property from code, you need to implement INotifyPropertyChanged interface or use Dependency properties.
<Grid x:Name="LayoutRoot">
<TextBox Text="{Binding Test, Mode=TwoWay}" />
</Grid>
public class MainPage : PhoneApplicationPage, INotifyPropertyChanged
{
private string test;
public string Test
{
get { return this.test; }
set
{
this.test = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Test"));
}
}
public MainPage()
{
InitializeComponents();
LayoutRoot.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
}
This is a stupid example since you can access your TextBox any time from MainPage, this has much more sense if you are displaying model objects with DataTemplates.
(I typed this on phone, hope it compiles..)

i got my solution as: var b = new Binding{ElementName = "currency", Path = new PropertyPath("Text")}; Textblock txt = new TextBlock(); txt.SetBinding(TextBlock.TextProperty, b);

Related

Data binding property not working

first of all sorry for my english.
I am developing a WP7 app, and I still haven't completely understood the data binding structure. I have a page that has some data obtained through data binding. Data is generated within the .cs, and it works fine.
But on another page I have some data that is obtained from data binding too, but I want it to come from a UI input text instead. It's simple, just a textbox and a textblock, so the user writes something on the textbox and so it shows up on the textblock that's on the same page. But it's not working, the textblock remains empty.
It's something like this:
<TextBox Name="TestInput">
<TextBlock Text="{Binding TestText}">
Above is what's on the XAML.
public partial class NewItem : PhoneApplicationPage
{
public String TestText { get; set; }
public NewItem()
{
InitializeComponent();
TestText = "TestInput.Text";
}
}
And this above is what's on the C#.
BUT!! It doesn't end here. Since the textblock wasn't showing anything, I ended desperately trying to assign some plain String to the TestText property. Like this:
TestText = "HELLO WORLD";
But when the app starts and the page loads, the textblock shows nothing. I just don't understand what am I missing, or doing wrong.
I will appreciate if someone could clear me up the databinding structure, or at least explain me what did I do wrong so I can figure it out myself.
Thanks in advance guys!
You have to assign the DataContext before you want the binding effect.So whenever there is a change in the text box, you write the code in the textchanged event.
this.DataContext=TestText
And one more change that you need to perform is that you are not actually setting the property.It should be like
TestText=TestInput.Text
for your understanding of binding i am putting a simple working example..just follow this..
this is you page on which you bind the data of textbox to someproperty textboxText..when you finished writing in this textbox.then all the writtentext automatically come ino this property. and this property is also binded to textbloack so when your textbloack got focus it will got to the get of the property and automatically fill it.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Horizontal" >
<TextBox x:Name="testTextbox" Height="50" Width="200" Text="{Binding TextboxText,Mode=TwoWay}" />
<TextBlock x:Name="testTextblock" Height="50" Width="1000" Text="{Binding TextboxText,Mode=OneWay}" Foreground="White" />
</StackPanel>
</Grid>
this is your page.cs class in which i have also shown you how to implement inotifyproperty changed..it will help you in future..
public sealed partial class MainPage : Page,INotifyPropertyChanged
{
public MainPage()
{
this.InitializeComponent();
this.DataContext = this;
}
private string _TextboxText;
public string TextboxText
{
get
{
return _TextboxText;
}
set
{
_TextboxText = value;
FirePropertyChanged("TextboxText");
testTextblock.UpdateLayout();
}
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
public event PropertyChangedEventHandler PropertyChanged;
protected void FirePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

MVVM Binding Problems with Pivot ItemTemplates Windows Phone 7

I have a Pivot element that has a header template and an itemtemplate with a listbox which also has a itemtemplate. The header template is bound to a list of "DOWS" which i create via code. This works fine. Each DOW has a entityset TDs and i want to bind the listbox itemtemplate to this source. Once i bound it, deleting an item updates the ui fine but adding an item doesn't update the ui.
the entityset is based off of the "Local database with mvvm" example here:
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh286405(v=vs.105).aspx
I've researched for a few days and cant find anything helpful. some solutions i found where to wrap the entityset in a observable collection but that didnt seem to work. Another one was to use BindingLists, but entitySets dont have "ToBindingList()" for windows phone 7. Ive created observable collections in my ViewModel that i could bind to, but then i have no way of telling the listbox itemtemplate which collection to bind to when its created.
Any ideas?
I Can post more code if needed.
Thanks!!
Example Observablen Collections in ViewModel
private ObservableCollection<TDItem> _twoDaysAgoItems;
public ObservableCollection<TDItem> TwoDaysAgoItems
{
get { return _twoDaysAgoItems; }
set
{
_twoDaysAgoItems = value;
NotifyPropertyChanged("TwoDaysAgoItems");
}
}
private ObservableCollection<TDItem> _yesterdayItems;
public ObservableCollection<TDItem> YesterdayItems
{
get { return _yesterdayItems; }
set
{
_yesterdayItems = value;
NotifyPropertyChanged("YesterdayItems");
}
}
private ObservableCollection<TDItem> _todayItems;
public ObservableCollection<TDItem> TodayItems
{
get { return _todayItems; }
set
{
_todayItems = value;
NotifyPropertyChanged("TodayItems");
}
}
EntitySet
private EntitySet<TDItem> _tds;
[Association(Storage = "_ts", OtherKey = "_dowId", ThisKey = "Id")]
public EntitySet<TDItem> TDs
{
get { return this._tds;
}
set {
NotifyPropertyChanging("TDs");
this._tds.Assign(value);
NotifyPropertyChanged("TDs");
}
}
public DOW()
{
_tds = new EntitySet<TDItem>(
new Action<TDItem>(this.attach_TD),
new Action<TDItem>(this.detach_TD)
);
}
Pivot
<controls:Pivot x:Name="TDPivotDisplay" SelectedIndex="2" Margin="0,-10,0,0" Grid.Row="0" Title="TD" Foreground="White" FontWeight="light" VerticalAlignment="Top" FontSize="29.333" Style="{StaticResource PivotStyle1}" FontFamily="{StaticResource Akzidenz Grotesk}">
<controls:Pivot.HeaderTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="DOW" Foreground="{Binding Colour}" FontSize="110" FontFamily="{StaticResource Akzidenz Grotesk}" Text="{Binding Header}"/>
<TextBlock x:Name = "FullDate" Foreground="{Binding Colour}" FontWeight="light" FontSize="30" FontFamily="{StaticResource Akzidenz Grotesk}" HorizontalAlignment="center" Text="{Binding Date}"/>
</StackPanel>
</DataTemplate>
</controls:Pivot.HeaderTemplate>
<controls:Pivot.ItemTemplate>
<DataTemplate>
<Grid Height="421">
<ListBox ItemsSource = "{Binding TDs}" ItemTemplate = "{StaticResource ListboxItemTemp}" x:Name ="TDLists" Margin="12, 0, 12, 0" Width="440"/>
</Grid>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>

Get selecteditem from listbox using MVVM

I'm using MVVM in this project, I have a listbox which bind to a collection of Customers. I want to create an event to navigate a detailsPage using id of the elementselected:
<ListBox ItemsSource="{Binding Customers}" x:Name="state_list" SelectionChanged="state_list_SelectionChanged">
<i:Interaction.Triggers>
<i:EventTrigger EventName="selectionchanged">
<cmd:EventToCommand Command="{Binding stateSelectedCommand}" PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding nom}" />
<!--TextBlock Text="{Binding LastName}" />
<TextBlock Text="{Binding Text, ElementName=tbCount}" /-->
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I can't figure out how to get the selected item to add it to the uri and then use it to get data. An example or tutorial would be helpful. Thanks :)
I would create a "SelectedCustomer" property in the ViewModel (next to you Customers property) and bind it to the SelectedItem. Then, on the setter of that property you can navigate to your desired page. This way you eliminate the messy events and command.
<ListBox x:Name="state_list
ItemsSource="{Binding Customers}"
SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}">
...
public Customer SelectedCustomer
{
get
{
return _selectedCustomer;
}
set
{
if (value != null)
{
_selectedCustomer = value;
//Navigate to your page here, either with Navigator class or any other mechanism you have in place for changing content on screen
}
}
}
AlexDrenea gives you a good way of binding SelectedItem to a property on your viewmodel. If you are wanting to navigate based on this in an MVVM architecture, I would suggest using messaging to get it done.
I cover this in a blog post I did a while back, but the short summary of doing this within MVVMLight, is to create a Navigator class that sits at the application level.
public class Navigator
{
private PhoneApplicatoinFrame RootFrame;
public Navigator(PhoneApplicationFrame frame)
{
RootFrame = frame;
RegisterMessages();
}
private void RegisterMessages()
{
Messenger.Default.Register<ShowTrackerMessage>(this, ShowTracker);
}
private void ShowTracker(ShowTrackerMessage msg)
{
RootFrame.Navigate(new Uri("/Views/ItemLocationCompassView.xaml", UriKind.RelativeOrAbsolute));
}
}
Then, as part of your application start-up, create it and pass it a reference to your RootFrame:
private static Navigator _navigator;
public static Navigator Nav
{
get { return _navigator; }
}
...
_navigator = new Navigator(this.RootFrame);
Then, you have a couple choices on how you send the Navigation message.
Option 1: In your ViewModel, hook into the PropertyChanged event (part of INotifyPropertyChanged), and send the appropriate message when your SelectedItem property changes.
Option 2: Tie into the SelectionChanged event of your ListBox. I use the MVVMLight's EventToCommand to send that event to a RelayCommand in my ViewModel, then react appropriately to send the message to the Navigator object.
I cover this in more detail at: http://www.smartchitecture.com/?p=27

WP7: Binding to an element outside pivot.itemtemplate

I've been struggling for a while on this. I'm a bit of a newbie, but i lurked a lot and still couldn't find a solution to my problem, so I decided to post my question here.
I'm binding a pivot to a collection of objects I want to display to create a gallery. Here is my pivot control bound to a list called gallery, where each object contains 2 strings (url and description).
<controls:Pivot ItemsSource="{Binding gallery}" Grid.Row="0" x:Name="galleryPivot">
<controls:Pivot.ItemTemplate>
<DataTemplate>
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Image Source="{Binding url}" />
<Grid Visibility="{Binding ElementName=galleryPivot, Path=DataContext.ShowDetail}">
<ListBox>
<ListBoxItem>
<StackPanel>
<TextBlock Text="{Binding description}" />
</StackPanel>
</ListBoxItem>
</ListBox>
</Grid>
</Grid>
</StackPanel>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
The datacontext is the viewmodel and initialized in the constructor of the page.
Here is my ViewModel:
public class GalleryViewModel : INotifyPropertyChanged
{
public List<Gallery> gallery
{
get { return Globals.pictures; }
}
private Visibility _showDetail = Visibility.Collapsed;
public Visibility ShowDetail
{
get { return _showDetail; }
set {
_showDetail = value;
RaisePropertyChanged("ShowDetail");
}
}
public GalleryViewModel()
{ }
public event PropertyChangedEventHandler PropertyChanged = delegate { return; };
protected void RaisePropertyChanged(string propertyName)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The gallery object is a list in my ViewModel, as the ShowDetail property. As ShowDetail is outside the scope, I tried to set ElementName as explained here.
The pivot binds well to the gallery list, but when I change the value of ShowDetail, the grid won't hide. I also tried to set ElementName to LayoutRoot but it still won't work.
My question, how can I bind the visibility when it is outside the scope of the itemtemplate?
Within a DataTemplate the ElementName binding refers only to the names of elements that are within that DataTemplate. The data context within your data template is the Gallery instance, not the GalleryViewModel. You could move the ShowDetail property down to the Gallery class instead.
If you'd rather not do that, then an alternative would be to use a proxy for the data context, which you add as a resource to the page and bind to the page's data context (a GalleryViewModel instance presumably). You can then reference that resource as you would any other resource to get at the parent data context.
If you're not familiar with this proxy concept, then Dan Wahlin's post on the subject should help.

What is the proper way to perform page navigation on ListBox selection changes

I'm trying the MVVM Light Toolkit. Though I still think having multiple ViewModels for such small apps is overkill, I like the concepts. What I still can't quite understand is how (or I should say "what is the recommended way") to navigate from one page to another when the selection changes in a ListBox.
The big problem with this toolkit is that it forces you to learn MVVM via other sources before using it, rather than show you what (its vision of) MVVM is from within the framework, accompanying samples and documentation. Are there samples out there showing the different concepts? And please, no videos.
Have you tried modifying your ListBox ItemTemplate to have each item be a HyperlinkButton and just setting the NavigateURI attribute to the Page you want to navigate to?
I still have not figured out how to do this (navigate to a details page upon selection changed in a listbox) without any codebehind in the view. However, if you are OK with having just a little codebehind in the view here's what I recommend:
<ListBox x:Name="MainListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}"
SelectionChanged="MainListBox_SelectionChanged"
SelectedItem="{Binding Path=SelectedListItem, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17" Width="432">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Style="{StaticResource PhoneTextExtraLargeStyle}"/>
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
First, per above bind to the SelectedItem property of the Listbox with a TwoWay binding to a property in your ViewModel (SelectedListItem in the above).
Then in your codebehind for this page implement the handler for MainListBox_SelectionChanged:
// Handle selection changed on ListBox
private void MainListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If selected index is -1 (no selection) do nothing
if (MainListBox.SelectedIndex == -1)
return;
// Navigate to the new page
NavigationService.Navigate(new Uri("/DetailsPage.xaml", UriKind.Relative));
}
This is the only codebehind you need in your main view.
In your main ViewModel you need a SelectedListItem property:
public const string SelectedListItemPropertyName = "SelectedListItem";
private ItemViewModel _SelectedListItem;
/// <summary>
/// Sample ViewModel property; this property is used in the view to display its value using a Binding
/// </summary>
/// <returns></returns>
public ItemViewModel SelectedListItem
{
get
{
return _SelectedListItem;
}
set
{
if (value != _SelectedListItem)
{
_SelectedListItem = value;
RaisePropertyChanged(SelectedListItemPropertyName);
}
}
}
Now, the trick to getting the context passed to your details page (the context being what list item was selected) you need to setup the DataContext in your Details view:
public DetailsPage()
{
InitializeComponent();
if (DataContext == null)
DataContext = App.ViewModel.SelectedListItem;
}
Hope this helps.
eventually you'll want to do more than just navigate, potentially navigate after setting a custom object.
Here is a MVVM-light way of doing this.
You'll first want to bind your listbox selected item to a property in your viewmodel
<ListBox ItemsSource="{Binding Events}" Margin="0,0,-12,0" SelectedItem="{Binding SelectedEvent, Mode=TwoWay}">
Declare your SelectedEvent property
public const string SelectedEventPropertyName = "SelectedEvent";
private Event _selectedEvent;
public Event SelectedEvent
{
get {return _selectedEvent;}
set
{
if (_selectedEvent == value)
{
return;
}
var oldValue = _selectedEvent;
_selectedEvent = value;
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(SelectedEventPropertyName, oldValue, value, true);
}
}
You can then define an interaction trigger bound to the tap event
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<cmd:EventToCommand Command="{Binding EventPageCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
In your viewmodel, define your EventPageCommand as a RelayCommand:
public RelayCommand EventPageCommand { get; private set; }
public MainViewModel()
{
EventPageCommand = new RelayCommand(GoToEventPage);
}
and finally declare your GoToEventPage method
private void GoToEventPage()
{
_navigationService.NavigateTo(new Uri("/EventPage.xaml", UriKind.Relative));
}
note that you can do other actions before navigating to your new page, plus your selected item from your list box is currently set in the property you bound it too.

Resources