I'm very new to WPF and currently learning the concepts of data binding.
my simplified XAML code. besides my problem (below) it works fine - quick and dirty placing of objects via GUI, will be cleaned up once works:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0">
</Grid>
<Grid Grid.Row="1">
<GroupBox Header="Change Type:" Height="95" Width="100" VerticalAlignment="Top" Margin="270,4,422,0" >
<StackPanel>
<RadioButton x:Name="RbtAdd" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Add" Foreground="Green"/>
</WrapPanel>
</RadioButton>
<RadioButton x:Name="RbtPull" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Pull" Foreground="Blue"/>
</WrapPanel>
</RadioButton>
<RadioButton x:Name="RbtModify" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Top" GroupName="modGroup" Checked="ModeRadio_Checked">
<WrapPanel>
<TextBlock Text="Modify" Foreground="DarkGray"/>
</WrapPanel>
</RadioButton>
</StackPanel>
</GroupBox>
<TextBlock x:Name="txtCurStock" HorizontalAlignment="Left" Margin="330,181,0,0" TextWrapping="Wrap" Text="{Binding Path=CurrentStock}" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" TextAlignment="Center"/>
<Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
<Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
<Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
<TextBlock Text="{Binding Path=NewStock}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
<TextBox x:Name="txtComment" HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
<Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>
<TextBlock x:Name ="txtModindicator" HorizontalAlignment="Left" Margin="433,181,0,0" TextWrapping="Wrap" Text="-" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>
<TextBlock x:Name ="txtResindicator" HorizontalAlignment="Left" Margin="663,182,0,0" TextWrapping="Wrap" Text="=" FontSize="20" FontWeight="Bold" VerticalAlignment="Top"/>
</Grid>
</Grid>
now the shortened c# code:
using System.Windows;
using System.Windows.Controls;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace SomeWPF
{
/// <summary>
/// Interaction logic for ModifyWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
public enum Mymode
{
add,
pull,
modify
}
public Mymode mode;
public MainWindow()
{
DataContext = this;
InitializeComponent();
CurrentStock = 5;
RbtPull.IsChecked = true;
ModEntry = 1;
}
private void ModeRadio_Checked(object sender, RoutedEventArgs e)
{
if (sender != null)
{
if (sender.Equals(RbtAdd))
{
mode = Mymode.add;
txtModindicator.Text = "+";
txtComment.Text = "Add";
lblOperation.Content = "Stock to Add:";
}
else if (sender.Equals(RbtPull))
{
mode = Mymode.pull;
txtModindicator.Text = "-";
txtComment.Text = "Pull";
lblOperation.Content = "Stock to Pull:";
}
else
{
mode = Mymode.modify;
txtModindicator.Text = "~";
lblOperation.Content = "Corrected Quantity:";
txtComment.Text = "Mod";
}
TxtEntry_TextChanged(sender, null);
}
}
private void TxtEntry_TextChanged(object sender, TextChangedEventArgs e)
{
if (mode == Mymode.add)
{
NewStock = CurrentStock + ModEntry;
}
else if (mode == Mymode.pull)
{
NewStock = CurrentStock - ModEntry;
}
else
{
NewStock = ModEntry;
}
}
#region Binding Stuff
private int _newstock;
public int NewStock
{
get
{
return _newstock;
}
set
{
if (_newstock != value)
{
_newstock = value;
OnPropertyChanged();
}
}
}
private int _modentry;
public int ModEntry
{
get
{
return _modentry;
}
set
{
if (_modentry != value)
{
_modentry = value;
OnPropertyChanged();
}
}
}
private int _currentstock;
public int CurrentStock
{
get
{
return _currentstock;
}
set
{
if (_currentstock != value)
{
_currentstock = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
So this window is a popup in a little program for an inventory storage for the users to enter movements of the inventory.
everything loads fine so far and I now wanted to do the quite simple calculation part. with "old" winforms c# you'd just take the values and update the text property of the result "manually" but of course we (I) want to learn new stuff and do stuff with data binding.
The code also does the calculation, but the trigger is somehow not what I want.
let's say current stock is 5
when window loads, the mode is set to Pull (RbtPull) and the user entry (Binding to ModEntry) is set to 1 via code. The NewStock therefore should be 4 which displays correctly. (yey)
Also the comment field (for debugging for now) displays the ModEntry value 1.
so far so good.
Now I enter 3 in the Stock to Pull field, but nothing happens. (I want it to react "realtime"). The new Stock is still displayed as 4, the comment is still displayed as 1.
When I leave the field (and click into the comment field) - the property change is detected and the Comment Field shows also 3 (=ModEntry) - so it's not "realtime" but only triggers when the field is losing focus, but that would be also acceptable.
The real problem is: The new Stock stays 4 and does not calculate.
Now when I enter the Stock to Pull field again and change the value to let's say 5, the New Stock field updates to 2 (so to the value I entered before 5-3=2)
Overwriting the field with again 5 will change the new Stock to 0.
So it's always "one step behind".
From what I have found i have an idea, that I need some kind of Binding Converter instead of my method of calculating things, but I can't really find anything suitable and am not familiar enough yet with data binding. Have tried out some things already directly in the binding variable code but none worked. If anyone could hint me in the right direction I'd be very thankful. (don't need a silver plate solution but just an idea what way to search (e.g. if the sort of binding I use makes sense at all or if there's something I have to add etc.).
Thanks a lot!
PS: of course if someone is motivated to give a silver plate solution I'd also be grateful. :) - and sorry for the bad english, no native speaker.
#nosale 's second link (see comments) provided the answer to the Problem.
Setting both XAML fields txtEntry and the Result field to UpdateSourceTrigger=PropertyChanged solved the issue.
so the correct block Looks like this now without changes to the c# code:
<Label Content="Current stock:" HorizontalAlignment="Left" Margin="289,156,0,0" VerticalAlignment="Top"/>
<Label x:Name ="lblOperation" Content="Stock to Pull:" HorizontalAlignment="Left" Margin="507,156,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="txtEntry" HorizontalAlignment="Left" Height="32" Margin="489,181,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="{Binding Path=ModEntry, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="120" FontSize="20" FontWeight="Bold" TextChanged="TxtEntry_TextChanged"/>
<Label Content="New Stock" HorizontalAlignment="Right" Margin="714,156,0,0" VerticalAlignment="Top" Width="68"/>
<TextBlock Text="{Binding Path=NewStock, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" Margin="0,186,10,0" TextAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="20" FontWeight="Bold" Width="68"/>
<TextBox x:Name="txtComment" HorizontalAlignment="Left" Height="86" Margin="289,233,0,0" TextWrapping="Wrap" Text="{Binding Path=ModEntry}" VerticalAlignment="Top" Width="493"/>
<Label Content="Comment:" HorizontalAlignment="Left" Margin="289,207,0,0" VerticalAlignment="Top"/>
Reason is, that textboxes have a Default UpdateSourceTrigger=LostFocus and not PropertyChanged to prevent updates with user having entered typos.
something new learned: WPF is cool and automatically handles non plausible values like null or strings and marks the field red! :)
thanks again for the links!
Related
So, I've got a UserControl which displays basic information about a customer extracted from a file object.
The control looks like this:
<UserControl x:Class="Ns.Gui.pnlDebtor"
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"
mc:Ignorable="d"
d:DesignHeight="230" d:DesignWidth="460" xmlns:my="clr-namespace:Ns.Gui">
<Grid>
<GroupBox Header="Debtor" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="groupBox1" VerticalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="56" />
<RowDefinition Height="28" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="380*" />
</Grid.ColumnDefinitions>
<Label Content="Name:" Height="28" HorizontalAlignment="Left" Name="lblName" VerticalAlignment="Top" />
<Label Content="Address:" Grid.Row="1" Height="28" HorizontalAlignment="Left" Name="lblAddress" VerticalAlignment="Top" />
<Label Content="Customer Nr.:" Grid.Row="2" Height="28" HorizontalAlignment="Left" Name="lblCustomerNr" VerticalAlignment="Top" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbName" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=DebtorName, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="1" Height="46" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbAddress" VerticalAlignment="Top" IsReadOnly="True" IsEnabled="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=Adresse, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbCustomerNr" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="True" />
<Button Content="Debtor Details" Grid.ColumnSpan="2" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="btnDetails" VerticalAlignment="Top" />
</Grid>
</GroupBox>
</Grid>
</UserControl>
My Name and Address Textboxes are bound to DebtorName and DebtorAddress properties of the pnlDebtor UserControl.
Codebehind is like so:
public partial class pnlDebtor : UserControl
{
private MyFile file = null;
public MyFile File
{
get
{
return file;
}
set
{
file = value;
tbCustomerNr.Text = file.CustomerNo;
}
}
private Contact debtor = null;
public Contact Debtor
{
get
{
if (debtor == null)
{
if (File != null)
{
debtor = AbstractDataObject.GetObject4ID<Contact>(File.DebtorID);
}
}
return debtor;
}
}
private Address debtorAddress = null;
public string Address
{
get
{
string result = string.Empty;
if (debtorAddress == null)
{
if (Debtor != null)
{
List<Address> lsAddresses = AbstractDataObject.GetObject4NonIdProperty<Address>("ContactID", Debtor.ID);
if (lsAddresses.Any())
{
debtorAddress = lsAddresses[0];
result += lsAddresses[0].Street + "\r\n"
+ lsAddresses[0].PostalCode + " " + lsAddresses[0].City;
}
}
}
else
{
result += debtorAddress.Street + "\r\n"
+ debtorAddress.PostalCode + " " + debtorAddress.City;
}
return result;
}
}
private string strDebtorName = string.Empty;
public string DebtorName
{
get
{
if (strDebtorName== string.Empty)
{
if (Debtor != null)
{
strDebtorName = Debtor.Name1;
if (Debtor.FirstName != null)
strSchuldnerName += ", " + Debtor.FirstName;
}
}
return strDebtorName;
}
}
public pnlDebtor()
{
InitializeComponent();
}
}
As you can see, unlike the Name and Address Textboxes, my CustomerNr Textbox is populated in the codebehind. When I pass in my file object, I extract the customer number and assign that value to the Text property of the appropriate Textbox. Both methods work, but the first method (Binding) seems to be prefered for WPF. Why?
To me, the disadvantages are:
1) Logic and presentation aren't separated. If I send my xaml to someone in design, there's a chance they could screw up my binding.
2) If I'm debugging and set a breakpoint, the Text property of my bound Textboxes is always an empty string. I can't see what's going on.
So, what are the advantages of using binding? Why is it the preferred method? Use small words. This is my first WPF project. :)
I think the missing link here is MVVM. Your bindings to properties in codebehind mean that that particular UserControl is still tightly coupled to that particular class. I wouldn't have said that it's any better than the version without bindings. The codebehind class won't compile unless the XAML page is bundled with it, because there's a reference to tbCustomerNr.Text.
Using MVVM and bindings, the ViewModel is completely isolated from the View. I can, if I like, delete the Views entirely from my program and the ViewModels will still compile without any complaints. This means that the ViewModel logic can be reused easily, and logic and UI development tasks can be separated cleanly.
I have implemented textblock in Listbox ItemTemplate/data template. It is databound to "Data" which is getting read from an xml file. Everything works fine but, the text is getting trimmed in textblocks and a there ia a blank space. I know the reason and it is due to limitations in textblock. Now i tried to use, Scrollable TextBlock for WP7 from Alex Yakhnin's Blog but I am not able to understand how to implement this in my project?
C# CODE:
string XMLTagNameBody = "page";
private void ParseHeaderBody()
{
XDocument SunderGutkaXMLInstance = XDocument.Load(xmlFileToOpen);
var XMLBody = from query in SunderGutkaXMLInstance.Descendants(XMLTagNameBody)
select new BodyContentClass
{
Data = (string)query.Element("data"),
};
ListBoxDisplayContent.ItemsSource = XMLBody;
}
public class BodyContentClass
{
string book;
string data;
public string Book
{
get { return book; }
set { book = value; }
}
public string Data
{
get { return data; }
set { data = value; }
}
}
XAML Code:
<ListBox Margin="0,25,0,32"
x:Name="ListBoxDisplayContent"
FontSize="48"
HorizontalAlignment="Center">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="ListBoxDisplayContentStackPanel"
Margin="10"
HorizontalAlignment="Center">
<TextBlock x:Name="MainContentDisplayTextBlock"
TextWrapping="Wrap"
Text="{Binding Data}"
TextAlignment="Center"
HorizontalAlignment="Center" />
<Image x:Name="dividerImage"
Stretch="Fill"
Source="/Assets/MainContentDivider.png"
Opacity="1"></Image>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Links for Alex Yakhnin's Blog/Scrollable TextBlock for WP7:
http://social.msdn.microsoft.com/Forums/windowsapps/en-US/3af9bc99-2526-49fc-b4a5-4170e12d11ab/do-textblocks-have-a-max-line-limit-if-so-how-do-i-increase-it?forum=wpdevelop
http://blogs.msdn.com/b/priozersk/archive/2010/09/08/creating-scrollable-textblock-for-wp7.aspx
You can create a custom control and than it can be added to your project like:
<StackPanel x:Name="ListBoxDisplayContentStackPanel" Margin="10"
HorizontalAlignment="Center">
<my:ScrollableTextBlock Text="{Binding Data}"
HorizontalAlignment="Left" Name="scrollableTextBlock1"
VerticalAlignment="Top" Height="618" Width="427" Margin="12,-11,0,0" />
<TextBlock x:Name="MainContentDisplayTextBlock"
TextWrapping="Wrap"
TextAlignment="Center"
HorizontalAlignment="Center" />
<Image x:Name="dividerImage"
Stretch="Fill"
Source="/Assets/MainContentDivider.png"
Opacity="1"></Image>
</StackPanel>
Where my is the namespace of your control.
I have the following DataTemplate:
<DataTemplate x:Key="ToDoListBoxItemTemplate">
<Grid x:Name="item2Expanded" HorizontalAlignment="Left" VerticalAlignment="Top" Width="480" Background="{Binding Converter={StaticResource RowColour}}" MinHeight="81">
<StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Width="420" Margin="60,0,0,0">
<TextBox x:Name="taskTitle" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ItemName}" VerticalAlignment="Top" Width="420" Background="{x:Null}" BorderBrush="{x:Null}" CaretBrush="#FF0080FF" SelectionBackground="#FFCFCFCF" Foreground="#FF4E4E4E" BorderThickness="3,3,3,6" FontSize="29.333" Style="{StaticResource listTextBoxTemplate}" InputScope="Text" SelectionForeground="#FF4E4E4E" KeyUp="taskTitle_KeyUp" LostFocus="taskTitle_LostFocus" Tap="taskTitle_Tap" IsReadOnly="True" Margin="0,1,0,0" DoubleTap="taskTitle_DoubleTap"/>
<TextBox x:Name="taskDetail" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Tea is an essential English beverage, it has a nice calming effect, and is often served alongside biscuits." VerticalAlignment="Top" Width="420" Background="{x:Null}" BorderBrush="{x:Null}" CaretBrush="#FF0080FF" SelectionBackground="#FFCFCFCF" Foreground="#FF878787" BorderThickness="3,0,3,6" FontSize="21.333" Style="{StaticResource listTextBoxTemplate}" InputScope="Text" SelectionForeground="#FF878787" Margin="0,-20,0,0" KeyUp="taskDetail_KeyUp" LostFocus="taskDetail_LostFocus" Padding="2,5,2,2" IsHitTestVisible="False"/>
<Grid Height="170" Margin="0,-20,0,0">
<Button x:Name="chooseDateButton" Content="27/06/2013" HorizontalAlignment="Left" Margin="6,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="#FF959595" Width="157" HorizontalContentAlignment="Left" FontSize="20" Style="{StaticResource selectorButtonTemplate}"/>
<Button x:Name="chooseTimeButton" Content="12:00" HorizontalAlignment="Left" Margin="146,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="#FF959595" Width="99" HorizontalContentAlignment="Left" FontSize="20" Style="{StaticResource selectorButtonTemplate}"/>
<Button x:Name="setOrClearButton" Content="REMIND ME" HorizontalAlignment="Left" Margin="228,13,0,0" VerticalAlignment="Top" BorderBrush="#FF959595" Foreground="White" Width="180" FontSize="20" Background="#FF959595" Style="{StaticResource greyButtonTemplate}"/>
<Button x:Name="deleteButton" Content="DELETE TASK" HorizontalAlignment="Left" Margin="6,85,0,0" VerticalAlignment="Top" BorderBrush="#FFEE4747" Foreground="White" Width="180" FontSize="20" Background="#FFEE4747" Style="{StaticResource redButtonTemplate}"/>
<Image x:Name="retractButton" Margin="347,107,21,11" Source="/Assets/retract.png" Stretch="Fill" Tap="retractButton_Tap"/>
</Grid>
</StackPanel>
<CheckBox x:Name="checkBox" IsChecked="{Binding IsComplete, Mode=TwoWay}" Content="" HorizontalAlignment="Left" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="{x:Null}" Width="72" BorderThickness="0" Template="{StaticResource checkBoxTemplate}" Checked="checkBox_Checked" Unchecked="checkBox_Unchecked"/>
</Grid>
</DataTemplate>
Where the Grid item2Expanded is placed dynamically in a ListBox (Name="allToDoItemsListBox"). Text is added to each item via bindings.
The image retractButton has Tap="retractButton_Tap", As shown in the code:
private void retractButton_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if (isItemExpanded == true)
{
// Compacts current item
itemGrid.Height = taskTitle.ActualHeight; // Restores itemGrid height to fit only taskTitle
taskTitle.IsReadOnly = true; // taskTitle becomes only double-tap editable, single tap to expand once more
taskDetail.IsHitTestVisible = false; // Stops overlapping taps
isItemExpanded = false;
}
// Adds the event handler for single tap event
tapTimer.Tick += new EventHandler(tapTimer_Tick);
tapTimer.Start();
}
private void tapTimer_Tick(object sender, EventArgs e)
{
// Stop timer
tapTimer.Tick -= new EventHandler(tapTimer_Tick);
tapTimer.Stop();
// Rest of the single tap function
if (isItemExpanded == false)
{
taskDetail.IsHitTestVisible = true;
taskDetail.IsEnabled = false;
// Expands current item
itemGrid.Height = double.NaN; // Sets itemGrid height to auto
isItemExpanded = true;
// Yeah... don't ask.
// Stops temporary text highlighting/auto jumping to keyboard
taskTitle.IsEnabled = false;
taskTitle.IsEnabled = true;
taskDetail.IsEnabled = true;
}
}
But I cannot access itemGrid, taskTitle, or taskDetail for this specific item. And I have no idea how to pass them to the tapTimer_Tick function.
I have been able to use the Tag="{binding itemID}" on elements, but that still hasn't allowed me to solve this issue.
How do I find the grid item2Expanded that the Tap originated from, and then access elements in the same grid by name?
If I want to access the same element as was clicked, then it's easy:
private void taskTitle_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
TextBox taskTitle = (TextBox)sender;
taskTitle.IsEnabled = false;
}
I've been trying to work out how to use Visual Tree Helper to solve this problem, but I have no idea how to do it.
I have a list picker when clicking on the control to select another item it seems to look like it is going to work but is all white I can sometimes get it to select another item but cant see what is selected until you are off of it. This is how I have it set up. When I set it to full mode the name space is the only thing that shows not the actual name of the item. All I am trying to do is upon loading the view I need to load the listPicker with values.
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Name="PickerItemTemplate" >
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TankTypeName}" Style="{StaticResource PhoneTextNormalStyle}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Name="PickerFullModeItemTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding TankTypeName}" Style="{StaticResource PhoneTextNormalStyle}" FontFamily="{StaticResource PhoneFontFamilyLight}"/>
</StackPanel>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<TextBox Height="72" HorizontalAlignment="Left" Margin="0,50,0,0" Name="TextBoxProjectName" Text="" VerticalAlignment="Top" Width="456" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="12,28,0,0" Name="TextBlockProjectName" Text="Tank Name:" VerticalAlignment="Top" />
<toolkit:ListPicker Header="Tank Type:" ItemsSource="{Binding TankTypes}"
ItemTemplate="{StaticResource PickerItemTemplate}"
FullModeItemTemplate="{Binding PickerFullModeItemTemplate}"
SelectedItems="{Binding SelectedTankTypes,Mode=TwoWay}"
Height="100" HorizontalAlignment="Left"
Margin="6,144,0,0" Name="ListPickerTankType"
VerticalAlignment="Top" Width="444" >
</toolkit:ListPicker>
</Grid>
View Model
private List<TankType> _tankType;
private ObservableCollection<Object> _selectedTankType= new ObservableCollection<object>();
/// <summary>
/// Collection of Tank Type objects.
/// </summary>
public List<TankType> TankTypes
{
get
{
return _tankType;
}
set
{
if (value != _tankType)
{
_tankType = value;
NotifyPropertyChanged("TankType");
}
}
}
public ObservableCollection<object> SelectedTankTypes
{
get
{
return _selectedTankType;
}
set
{
if (_selectedTankType == value)
{
return;
}
_selectedTankType = value;
NotifyPropertyChanged("SelectedTankTypes");
}
}
This is a edit page so in the constructor of the view.
public TaskDetail()
{
InitializeComponent();
var tankTypeViewModel = new ViewModels.TankVewModel();
tankTypeViewModel.GetTankTypes();
ListPickerTankType.DataContext = tankTypeViewModel;
}
Revised OK I removed the height on the listpicker and now can see it made it bigger so the three items are there. I just cant seem to change the font color to black so I can see it when you click on the listpicker.
Figured it out. I needed to remove the height and set the foreground color to black.
Basically, I'm trying to take information entered by the user on one page and print it out to another page via a "printer friendly" version, or report, of something. I have a MainPage.xaml that is, as the name suggests, my main page, but in a window there is the subpage AdCalculator.xaml where the user enters the information and PrintEstimate.xaml that is navigated to via a button on AdCalculator.
I would like to be able to transfer the information entered in the textboxes from AdCalculator and print it out via text blocks in PrintEstimate. So in order to do that I have the following code:
Views.AdCalculator AdCalc = new Views.AdCalculator();
string PrintCompanyName = AdCalc.CompanyName;
string PrintContactName = AdCalc.txt_CustomerName.Text;
string PrintBillingAddress1 = AdCalc.txt_BillingAddress.Text;
string PrintBillingAddress2 = AdCalc.txt_BillingAddressLine2.Text;
string PrintPhoneNumber = AdCalc.txt_PhoneNumber.Text;
string PrintNumOfAds = AdCalc.txt_NumofAds.Text;
string PrintRateOfPlay = AdCalc.Cmb_Rate.SelectedValue.ToString();
string PrintNumOfMonths = AdCalc.txt_NumofMonths.Text;
string PrintTotalDue = AdCalc.txt_InvoiceSummary_TotalDue.Text;
PrintEstimate PrintEstimatePage = new PrintEstimate();
PrintEstimatePage.txt_CompanyName.Text = PrintCompanyName;
PrintEstimatePage.txt_CustomerName.Text = PrintContactName;
PrintEstimatePage.txt_BillingAddress.Text = PrintBillingAddress1;
PrintEstimatePage.txt_BillingAddressLine2.Text = PrintBillingAddress2;
PrintEstimatePage.txt_PhoneNumber.Text = PrintPhoneNumber;
PrintEstimatePage.txt_InvoiceSummary_NumofAds.Text = PrintNumOfAds;
PrintEstimatePage.txt_InvoiceSummary_RateofPlay.Text = PrintRateOfPlay;
PrintEstimatePage.txt_InvoiceSummary_NumOfMonths.Text = PrintNumOfMonths;
PrintEstimatePage.txt_EstimateTotal.Text = PrintTotalDue;
Only problem is, when I instantiate the new AdCalculator page, it clears the values, so nothing is actually retained as far as user-input goes. Following a lead from a colleague, I believe all I need to do is change the line
Views.AdCalculator AdCalc = new Views.AdCalculator();
to
Views.AdCalculator AdCalc = (AdCalculator)Application.OpenForms["AdCalculator"];
except the "Apllication.OpenForms" doesn't register. I know there are a lot of differences in the way C# code-behind is laid out for silverlight applications, so I didn't know if there was an equivalent that anyone knew about to "Application.OpenForms" that would help solve my issue or if there was any other way to go about getting my task done.
If I understand your question correctly you simply want to get some user input and display it.
I suggest you start by defining a class that will represent the data you are inputting,
for example:
public class Customer
{
public string ContectName { get; set; }
public string BillingAddress1 { get; set; }
public string BillingAddress2 { get; set; }
public string PhoneNumber { get; set; }
public int NumOfAds { get; set; }
public double RateOfPlay { get; set; }
public int NumOfMonths { get; set; }
public double TotalDue { get; set; }
}
On the page where the user inputs data you then create an instance
of this class, either by manually creating an instance and setting
its properties when the user submits (similar to what you are doing in your code)
or use databinding to your advantage (which is what I prefer).
Let's say for example you are inputting data on your MainPage
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = new Customer();
}
Now you can bind the controls. Let's say you're using a grid:
<Grid x:Name="LayoutRoot" Background="White">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<sdk:Label Content="Billing Address 1:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="billingAddress1TextBox" Text="{Binding Path=BillingAddress1, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Billing Address 2:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="billingAddress2TextBox" Text="{Binding Path=BillingAddress2, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Contect Name:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="contectNameTextBox" Text="{Binding Path=ContectName, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Num Of Ads:" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="3" Name="numOfAdsTextBox" Text="{Binding Path=NumOfAds, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Num Of Months:" Grid.Column="0" Grid.Row="4" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="4" Height="23" HorizontalAlignment="Left" Margin="3" Name="numOfMonthsTextBox" Text="{Binding Path=NumOfMonths, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Phone Number:" Grid.Column="0" Grid.Row="5" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="3" Name="phoneNumberTextBox" Text="{Binding Path=PhoneNumber, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Rate Of Play:" Grid.Column="0" Grid.Row="6" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="6" Height="23" HorizontalAlignment="Left" Margin="3" Name="rateOfPlayTextBox" Text="{Binding Path=RateOfPlay, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<sdk:Label Content="Total Due:" Grid.Column="0" Grid.Row="7" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="7" Height="23" HorizontalAlignment="Left" Margin="3" Name="totalDueTextBox" Text="{Binding Path=TotalDue, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
</Grid>
</Grid>
When the user clicks the submit button, you can use something like this:
private void Button_Click(object sender, RoutedEventArgs e)
{
var currentCustomer = this.DataContext as Customer;
var previewWindow = new PrintPreviewWindow(currentCustomer);
previewWindow.Show();
}
For this to work you'll need to have a Silverlight ChildWindow like this:
public partial class PrintPreviewWindow : ChildWindow
{
public PrintPreviewWindow(Customer customer)
{
InitializeComponent();
this.DataContext = customer;
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
}
So your MainPage creates a new instance of the PrintPreviewChildWindow (could be a page as well if you prefer) and passes along the customer instance. The ChildWindow can then do whatever it wants with it. When the ChildWindow closes, you'll probably want to empty the input page, you can do this by simply setting the data context again:
this.DataContext = new Customer();
I'm guessing this is what you are looking for.
Try to get into the whole data binding stuff, it will save you lots and lots of lines of code. And let us know if this answers your question or if you have more :-)