Binding does not work for TemplateSelector - wpf

I have one part of the view is dynamic based on a TemplateSelector. However, the binding does not work for the controls in the DataTemplate.(The controls do show on screen, just the conetent/texts are empty). I suspect it's a DataContext issue, but couldn't figure out after a lot of searching on line. Here is my XAML:
<Grid>
<Grid.DataContext>
<local:MyViewModel/>
</Grid.DataContext>
<Grid.Resources>
<DataTemplate x:Key="T1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="Music"
Style="{StaticResource ResourceKey=textBlockStyle}" />
<TextBox Grid.Column="1"
Grid.Row="0"
Style="{StaticResource ResourceKey=textBoxStyle}"
Text="{Binding Path=MusicName}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="T2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="Currency"
Style="{StaticResource ResourceKey=textBlockStyle}" />
<ComboBox Grid.Column="1"
Grid.Row="0"
Style="{StaticResource ResourceKey=comboBoxStyle}"
ItemsSource="{Binding Path=Currency_List}"
SelectedItem="{Binding Path=Currency}" />
</Grid>
</DataTemplate>
<local:ProductTypeTemplateSelector T1="{StaticResource ResourceKey=T1}"
T2="{StaticResource ResourceKey=T2}"
x:Key="myTemplateSelector" />
<Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
<RowDefinition Height="40"/>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<!-- This biding works -->
<TextBlock Grid.Row="0"
Text="{Binding Path=MusicName}"/>
<!-- This biding does not work -->
<ContentControl Grid.Row="1"
Name="ccc"
Content="{Binding Path=Product_Type}"
ContentTemplateSelector="{StaticResource myTemplateSelector}">
</ContentControl>
</Grid>
This is my View Model (Technically, it is View Model and Model mixed together. I am not really implementing a full MVVM pattern)
public class MyViewModel: INotifyPropertyChanged
{
public MyViewModel()
{
SetLists();
}
protected void SetLists()
{
SetList_Product_Type();
SetList_Currency();
}
protected void SearchAndPopulate()
{
string query = string.Format("select * from dbo.vehicle_attributes where ticker like '%{0}%'", Search_Text);
DataView dv = DAL.ExecuteQuery(query);
if (dv.Count > 0)
{
DataRowView dvr = dv[0];
Vehicle_Id = int.Parse(dvr["vehicle_id"].ToString());
Product_Type = dvr["product_type_name"].ToString();
Vehicle_Name = dvr["vehicle_name"].ToString();
Is_Onshore = dvr["domicile_name"].ToString() == "Onshore";
Currency = dvr["currency"].ToString();
CUSIP = dvr["CUSIP"].ToString();
ISIN = dvr["isin"].ToString();
Ticker = dvr["ticker"].ToString();
Valoren = dvr["valoren"].ToString();
PC_Class = PC_Class_List.Find(x => x.Class_Name == dvr["class_name"].ToString());
Implementation_Type = Implementation_Type_List.Find ( x => x.Implementation_Type_Name == dvr["implementation_type_name"].ToString());
Price_Frequency = Price_Frequency_List.Find( x => x.Price_Frequency_Name == dvr["price_freq_name"].ToString());
Status = Status_List.Find( x => x.Status_Name == dvr["status_name"].ToString());
if (!string.IsNullOrEmpty(dvr["last_status_update"].ToString()))
{
Status_Date = DateTime.Parse(dvr["last_status_update"].ToString());
}
else
{
Status_Date = DateTime.MinValue;
}
switch (Product_Type)
{
case "Mutual Fund":
query = string.Format("select lf.dividend_currency, i.ticker from dbo.liquid_funds lf " +
"left join dbo.vehicles i on i.vehicle_id = lf.index_id " +
"where lf.vehicle_id ='{0}'",Vehicle_Id);
DataView dv_mutual_fund = DAL.ExecuteQuery(query);
if(dv_mutual_fund.Count > 0)
{
DataRowView dvr_mutual_fund = dv_mutual_fund[0];
Dividend_Currency = dvr_mutual_fund["dividend_currency"].ToString();
Benchmark_Ticker = dvr_mutual_fund["ticker"].ToString();
}
break;
default:
break;
}
}
}
public ICommand SearchVehicleCommand
{
get
{
return new Command.DelegateCommand(SearchAndPopulate);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
//ProductType
protected List<string> _product_Type_List = new List<string>();
public List<string> Product_Type_List
{
get
{
return _product_Type_List;
}
set
{
_product_Type_List = value;
OnPropertyChanged("Product_Type_List");
}
}
protected void SetList_Product_Type()
{
string query = "SELECT * FROM dbo.product_types WHERE is_enabled = 1";
DataView dv = DAL.ExecuteQuery(query);
List<string> l = new List<string>();
for (int i = 0; i < dv.Count; i++)
{
l.Add(dv[i]["product_type_name"].ToString());
}
Product_Type_List = l;
}
protected string _product_type;
public string Product_Type
{
get
{
return _product_type;
}
set
{
_product_type = value;
OnPropertyChanged("Product_Type");
SetList_Implementation_Type();
}
}
//Currency
protected List<string> _currency_List = new List<string>();
public List<string> Currency_List
{
get
{
return _currency_List;
}
set
{
_currency_List = value;
OnPropertyChanged("Currency_List");
}
}
protected void SetList_Currency()
{
string query = "SELECT currency FROM dbo.currencies";
DataView dv = DAL.ExecuteQuery(query);
List<string> l = new List<string>();
for (int i = 0; i < dv.Count; i++)
{
l.Add(dv[i]["currency"].ToString());
}
Currency_List = l;
}
protected string _currency;
public string Currency
{
get
{
return _currency;
}
set
{
_currency = value;
OnPropertyChanged("Currency");
}
}
// Music Name
protected string _musicName;
public string MusicName
{
get
{
return _musicName;
}
set
{
_musicName = value;
OnPropertyChanged("MusicName");
}
}
}
This is the class interface (sorry for the formatting above, but somehow I can't get it right):
And this is my DelegateCommand class:
public class DelegateCommand : ICommand
{
private readonly Action _action;
public DelegateCommand(Action action)
{
_action = action;
}
public void Execute(object parameter)
{
_action();
}
public bool CanExecute(object parameter)
{
return true;
}
}
This is the DataTemplateSelector:
public class MyTemplateSelector : DataTemplateSelector
{
public DataTemplate T1 { get; set; }
public DataTemplate T2 { get; set; }
public override DataTemplate SelectTemplate(object item,
DependencyObject container)
{
string product_type = (string)item;
if (product_type == "Type1")
return T1;
else
return T2;
}
}

The DataContext of a DataTemplate is set to the object that it is bound to. So in your case the DataContext for your Templates are Product_Type and you are expecting it to be MyViewModel.
There is a workaround for what you need. It uses a RelativeSource binding and FindAncester to access the DataContext of the Parent object.
Your DataTemplate bindings should look like this:
XAML
<DataTemplate x:Key="T1">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="Music"
Style="{StaticResource ResourceKey=textBlockStyle}" />
<TextBox Grid.Column="1"
Grid.Row="0"
Style="{StaticResource ResourceKey=textBoxStyle}"
Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.MusicName}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="T2">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Grid.Row="0"
Text="Currency"
Style="{StaticResource ResourceKey=textBlockStyle}" />
<ComboBox Grid.Column="1"
Grid.Row="0"
Style="{StaticResource ResourceKey=comboBoxStyle}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.Currency_List}"
SelectedItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContentControl}}, Path=DataContext.Currency}" />
</Grid>
</DataTemplate>
From MSDN
Find Ancestor - Refers to the ancestor in the parent chain of the data-bound element. You can use this to bind to an ancestor of a specific type or its subclasses.
The AncestorType attribute goes up the visual tree and finds the first Ancestor of the given type, in this case it's looking for ContentControl the path to the required property can then be set relative to this.
Update
Think of a template as a guide on how to display an object. The DataContext of the DataTemplate is going to be whatever object it is asked it to display.
In this case the ContentControl is told to display Product_Type and, depending on the value of Product_Type, to use a particular Template. Product_Type is given to the DataTemplate and becomes the DataContext.
WPFTutorials has some good examples.

Related

How to get datacontext of an event emitting item control?

I have a bunch of buttons being render inside an items control. I want to get access to the data context of the clicked button. How can I achieve that?
Model:
public class RunYear
{
public RunYear(int year)
{
Year = year;
Months = new Month[3];
}
public int Year { get; set; }
public Month[] Months { get; set; }
}
public class Month
{
public int ColumnIndex { get; set; }
public string MonthName { get; set; }
// some other props
}
Code behind:
public partial class MainWindow : Window
{
private ObservableCollection<RunYear> _years = new ObservableCollection<RunYear>();
public ObservableCollection<RunYear> Years { get{return _years; } }
public MainWindow()
{
DataContext = this;
InitializeComponent();
GenerateData();
}
private void GenerateData()
{
for (int i = 2010; i < 2015; i++)
{
var runYear = new RunYear(i);
runYear.Months[0] = new Month() { ColumnIndex = 0, MonthName = $"Jan {i}" };
runYear.Months[1] = new Month() { ColumnIndex = 1, MonthName = $"Feb {i}" };
runYear.Months[2] = new Month() { ColumnIndex = 2, MonthName = $"Mar {i}" };
Years.Add(runYear);
}
}
public void OnClick(object sender, RoutedEventArgs args)
{
// how do I get the databound item?
var cp = sender as ContentPresenter; //doesn't work
var vm = cp?.Content as Month;
}
}
XAML:
<Grid>
<ItemsControl Name="icYears" ItemsSource="{Binding Years}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="75"/>
</Grid.RowDefinitions>
<DockPanel Grid.Column="0" Grid.Row="0" >
<TextBox IsReadOnly="True" TextAlignment="Center" Text="{Binding Year}" />
</DockPanel>
<ItemsControl Grid.Column="1" Name="icMonths" ItemsSource="{Binding Months}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="75"></RowDefinition>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Click="OnClick" Content="{Binding MonthName}" Padding="2" Margin="2"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Do you mean like this?
private void Button_Click(object sender, RoutedEventArgs e)
{
var vm = (sender as FrameworkElement).DataContext;

How I can print listbox item count along with Expander header?

I want to print listbox item count alog with header of expander like
header1 (count) . How can I achieve this in WPF
You haven't provided any code for what you have done, such as if you are using a ViewModel or doing code-behind. There are multiple ways to go about it.
My ViewModel Way
In this example, I've made a ViewModel containing an ObservableCollection of string to populate the ListBox. The Expander header is bound to a property that is populated using a combination of the HeaderText and ItemCount.
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _headerText = string.Empty;
private string _headerTextFull = string.Empty;
private ObservableCollection<string> _listItems = new ObservableCollection<string>();
private int _itemCount = 0;
public ViewModel() { }
public string HeaderText
{
get { return _headerText; }
set
{
_headerText = value;
NotifyPropertyChanged("HeaderText");
UpdateHeader();
}
}
public string HeaderTextFull
{
get { return _headerTextFull; }
set
{
_headerTextFull = value;
NotifyPropertyChanged("HeaderTextFull");
}
}
public ObservableCollection<string> ListItems
{
get { return _listItems; }
set
{
_listItems = value;
NotifyPropertyChanged("ListItems");
ItemCount = (_listItems != null ? _listItems.Count : 0);
}
}
public int ItemCount
{
get { return _itemCount; }
set
{
_itemCount = value;
NotifyPropertyChanged("ItemCount");
UpdateHeader();
}
}
private void UpdateHeader()
{
HeaderTextFull = String.Format("{0} ({1})", _headerText, _itemCount);
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The XAML for the Window:
<Window x:Class="SO37192142.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Expander Grid.Row="0" Name="expander1" Header="{Binding Path=HeaderTextFull, FallbackValue='Items'}" IsExpanded="True">
<Grid>
<ListBox Name="listBox1" Width="Auto" Height="Auto" ItemsSource="{Binding Path=ListItems}" />
</Grid>
</Expander>
<Button Grid.Row="1" Content="Add an Item" Click="Button_Click" />
</Grid>
</Window>
The code-behind:
public partial class Window1 : Window
{
ViewModel myModel = new ViewModel();
public Window1()
{
InitializeComponent();
myModel.ListItems.CollectionChanged += new NotifyCollectionChangedEventHandler(ListItems_CollectionChanged);
myModel.HeaderText = "Items";
myModel.ListItems.Add("Item 1");
myModel.ListItems.Add("Item 2");
this.DataContext = myModel;
}
void ListItems_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
myModel.ItemCount = myModel.ListItems.Count;
}
void Button_Click(object sender, RoutedEventArgs e)
{
myModel.ListItems.Add("Another item");
}
}
When it starts, the Expander header will say "Items (2)". Every time the button is clicked, the header will update to show the new count.
Slight Variation of Above
Here's an example that provides the above example, but also adds a second list to demonstrate a different way. Notice the Expander.Header section.
<Window x:Class="SO37192142.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Expander Grid.Row="0" Grid.Column="0" Name="expander1" Header="{Binding Path=HeaderTextFull, FallbackValue='Items'}" IsExpanded="True">
<Grid>
<ListBox Name="listBox1" Width="Auto" Height="Auto" ItemsSource="{Binding Path=ListItems}" />
</Grid>
</Expander>
<!-- SECOND EXPANDER THAT DOESN'T RELY ON A VIEWMODEL -->
<Expander Grid.Row="0" Grid.Column="1" Name="expander2" IsExpanded="True">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding ElementName=listBox2, Path=Items.Count, UpdateSourceTrigger=PropertyChanged, StringFormat={}Items ({0})}" />
</StackPanel>
</Expander.Header>
<Grid>
<ListBox Name="listBox2" Width="Auto" Height="Auto" ItemsSource="{Binding Path=ListItems}" />
</Grid>
</Expander>
<Button Grid.Row="1" Grid.ColumnSpan="2" Content="Add an Item" Click="Button_Click" />
</Grid>
</Window>
Only Code Behind
If, for some reason, you are just using code-behind, you can do it this way:
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
((INotifyCollectionChanged)listBox1.Items).CollectionChanged += new NotifyCollectionChangedEventHandler(ListBox_CollectionChanged);
}
void ListBox_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
expander1.Header = "Items (" + listBox1.Items.Count + ")";
}
}

Not binding data from one window's Textbox to another window's Textbox

Data Binding from one textbox to another is not happen properly .Here is the below code am using.
EDIT:
Mainwindow xaml:
<Grid>
<TextBox Name="txtBox1" AcceptsReturn="True" Margin="0,0,203,148" VerticalScrollBarVisibility="Visible" LostFocus="txtBox1_LostFocus" TextChanged="txtBox1_TextChanged">
</TextBox>
<Button Content="ButtonToDisplay" Height="46" HorizontalAlignment="Left" Margin="362,71,0,0" Name="button1" VerticalAlignment="Top" Width="98" Click="button1_Click" />
</Grid>
CheckAddressWindow xaml:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="195"/>
<RowDefinition Height="28"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<GroupBox Name="grpFullName" Header="Name Details" BorderBrush="Black" BorderThickness="1" FontWeight="Bold" >
<Grid ShowGridLines="False">
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="50"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="15"/>
</Grid.RowDefinitions>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Name="lblstreet" Content="Street" VerticalAlignment="Top"></Label>
<TextBox Grid.Column="1" Name="txtStreet" VerticalAlignment="Stretch" Margin="0,0,0,5" TextChanged="txtStreet_TextChanged" Text="{Binding Path=szStreet Mode=OneWay}"></TextBox>
</Grid>
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="201"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Name="lblCity" Content="City" VerticalAlignment="Top"></Label>
<TextBox Grid.Column="1" Name="txtCity" VerticalAlignment="Top" Text="{Binding Path=szCityname,Mode=OneWay}"></TextBox>
</Grid>
<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Name="lblstate" Content="State/Province" VerticalAlignment="Top"></Label>
<TextBox Grid.Column="1" Name="txtState" VerticalAlignment="Top" Text="{Binding Path=szState}"></TextBox>
</Grid>
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Name="lblZip" Content="Zip/PostalCode" VerticalAlignment="Top" Grid.ColumnSpan="2"></Label>
<TextBox Grid.Column="2" Name="txtZip" VerticalAlignment="Top" Text="{Binding Path=iZip}"></TextBox>
</Grid>
<Grid Grid.Row="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.4*"/>
<ColumnDefinition Width="0.7*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Name="lblCountry" Content="Country/Region" VerticalAlignment="Top"></Label>
<ComboBox Grid.Column="1" Name="cbCountry" VerticalAlignment="Top" IsEditable="True" ></ComboBox>
</Grid>
</Grid>
</GroupBox>
<StackPanel Grid.Row="1" Orientation="Horizontal" FlowDirection="LeftToRight">
<CheckBox Name="chkFullAddress" Margin="5,8,5,5" Checked="CheckedEnabled" Unchecked="UncheckedEnabled" IsChecked="true"></CheckBox>
<Label Name="lblFullname" Content="Show this again when name is incomplete or unclear"></Label>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" FlowDirection="RightToLeft">
<Button Name="btnFullnameCancel" Content="Cancel" Margin="10,10,10,10" Width="50" Click="btnCheckAddressCancelClick"></Button>
<Button Name="btnFullnameOk" Content="Ok" Margin="10,10,10,10" Width="50" Click="btnCheckAddressOkClick"></Button>
</StackPanel>
</Grid>
Person.cs code:Edited
public string szStreet
{
get ;
set ;
}
public string szCityname
{
get ;
set ;
}
public string szState { get; set; }
public int iZip { get; set; }
public static bool bCheck { get; set; }
public static bool bCheckFullAddress { get; set; }
Mainwindow LostFocusEvent: Edited
private void txtBox1_LostFocus(object sender, RoutedEventArgs e)
{
if ((!string.IsNullOrEmpty(txtBox1.Text)) && (!string.IsNullOrWhiteSpace(txtBox1.Text)))
{
if (Person.bCheckFullAddress)
{
CheckAddressWindow ca = new CheckAddressWindow(txtBox1);
ca.ShowDialog();
}
}
else
{
CheckAddressWindow ca = new CheckAddressWindow(txtBox1);
ca.chkFullAddress.IsChecked = caObj.chkFullAddress.IsChecked;
ca.txtCity.Text = txtBox1.Text;
ca.ShowDialog();
}
}
ButtonClick event:Edited
private void button1_Click(object sender, RoutedEventArgs e)
{
caObj.chkFullAddress.IsChecked = (Person.bCheckFullAddress == true) ? true : false;
if (!string.IsNullOrEmpty(txtBox1.Text.Trim()))
{
CheckAddressWindow ca = new CheckAddressWindow(txtBox1);
ca.chkFullAddress.IsChecked = caObj.chkFullAddress.IsChecked;
ca.ShowDialog();
}
else
{
CheckAddressWindow ca = new CheckAddressWindow(txtBox1);
ca.chkFullAddress.IsChecked = caObj.chkFullAddress.IsChecked;
ca.ShowDialog();
ca.txtCity.Text = txtBox1.Text;
}
}
CheckAddressWindow.cs:Edited
public partial class CheckAddressWindow : Window
{
public static bool bChecked = true;
Person objPerson = new Person();
bool bCheckAddress = true;
TextBox txt = new TextBox();
public CheckAddressWindow()
{
InitializeComponent();
}
public CheckAddressWindow(TextBox txtName)
{
InitializeComponent();
txt = txtName;
StringCollection objSc = new StringCollection();
int iLinecount = txt.LineCount;
for (int iCount = 0; iCount < iLinecount; iCount++)
{
objSc.Add(txt.GetLineText(iCount));
}
if (objSc.Count.Equals(5))
{
objPerson.szStreet = (objSc[0] + objSc[1]).Trim();
objPerson.szCityname = objSc[2].Trim();
objPerson.szState = objSc[3].Trim();
objPerson.iZip = objSc[4].Trim();
}
if (objSc.Count.Equals(3))
{
objPerson.szStreet = (objSc[0] + objSc[1]).Trim();
string[] arrName = objSc[2].Split(',', ' ');
objPerson.szCityname = arrName[0].Trim();
objPerson.szState = arrName[1].Trim();
objPerson.iZip = arrName[2].Trim();
}
}
private void btnCheckAddressCancelClick(object sender, RoutedEventArgs e)
{
this.Close();
}
private void btnCheckAddressOkClick(object sender, RoutedEventArgs e)
{
if (!string.IsNullOrEmpty(txtCity.Text))
{
//txt.Text = txtStreet.Text + "\n" + txtCity.Text + "\n" + txtState.Text + "\n" + txtZip.Text + "\n" + cbCountry.SelectedValue;
objPerson.szStreet = txtStreet.Text.Trim();
objPerson.szCityname = txtCity.Text.Trim();
objPerson.szState = txtState.Text.Trim();
objPerson.iZip = Convert.ToInt32(txtZip.Text.Trim());
txt.Text = objPerson.szStreet + "\n" +objPerson.szCityname+","+txtState.Text + " " + txtZip.Text;
if (chkFullAddress.IsChecked == true)
{
bCheckAddress = true;
}
else
{
bCheckAddress = false;
}
}
this.Close();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
cbCountry.Items.Add("India");
cbCountry.Items.Add("US");
cbCountry.SelectedIndex = 0;
}
private void txtStreet_TextChanged(object sender, TextChangedEventArgs e)
{
}
private void CheckedEnabled(object sender, RoutedEventArgs e)
{
chkFullAddress.IsChecked = Person.bCheckFullAddress = true;
}
private void UncheckedEnabled(object sender, RoutedEventArgs e)
{
chkFullAddress.IsChecked = Person.bCheckFullAddress = false;
}
}
}
I am trying to bind data or text entered in mainwindow to checkaddresswindowxaml...as soon as the checkAddresswindow loads it shows all the text feilds are null,if i enter some data in checkaddress feild then click ok button it will show mainwindow.In mainWindow ,when click the button it binding and showing the two text box values.My issue for the first time its binding data to checkAddresswindow.How can i achieve this.am new to this concepts.If i did nay mistakes please rectify me.
Data binding is not happen...where i went wrong and which part of code i need to change to achieve it.
When running your app, do you see any Binding Errors in your debug output window?
I am not seeing where you are setting your DataContext for your CheckAddressWindow. I think you cut off the top of your XAML for that file.
Another problem may be that the "Person" object you are binding to in your CheckAddressWindow is not the same "Person" object being used by the MainWindow.
I would recommend that you have a Model that contains a Person object that both the MainWindow and the CheckAddressWindow bind to. This way, both windows are referring to the same person.
For info and tutorials on MVVM architecture for WPF, see the following link:
MVVM: Tutorial from start to finish?

Horizontal stretch list item in WP7 with grouping

I want to implement ListBox Grouping on WP7. I found this article is very useful. Actually I made the grouping works. But I got a problem with ListItem horizontal stretch. I guess I need to set ItemContainerStyle and change HorizontalContentAlignment as Stretch. But it doesn't work for this case (if set the ItemTemplate directly, it works). Any suggestions? Thanks a lot!
Here is the code, the ListItem is supposed to be stretched, but it's centered instead.
C#:
public class GroupingItemsControlConverter : IValueConverter
{
public object Convert(object value, Type tagetType, object parameter, CultureInfo culture)
{
var valueAsIEnumerable = value as IEnumerable;
if (null == valueAsIEnumerable)
{
throw new ArgumentException("GroupingItemsControlConverter works for only IEnumerable inputs.", "value");
}
var parameterAsGroupingItemsControlConverterParameter = parameter as GroupingItemsControlConverterParameters;
if (null == parameterAsGroupingItemsControlConverterParameter)
{
throw new ArgumentException("Missing required GroupingItemsControlConverterParameter.", "parameter");
}
var groupSelectorAsIGroupingItemsControlConverterSelector = parameterAsGroupingItemsControlConverterParameter.GroupSelector as IGroupingItemsControlConverterSelector;
if (null == groupSelectorAsIGroupingItemsControlConverterSelector)
{
throw new ArgumentException("GroupingItemsControlConverterParameter.GroupSelector must be non-null and implement IGroupingItemsControlConverterSelector.", "parameter");
}
// Return the grouped results
return ConvertAndGroupSequence(valueAsIEnumerable.Cast<object>(), parameterAsGroupingItemsControlConverterParameter);
}
private IEnumerable<object> ConvertAndGroupSequence(IEnumerable<object> sequence, GroupingItemsControlConverterParameters parameters)
{
// Validate parameters
var groupKeySelector = ((IGroupingItemsControlConverterSelector)(parameters.GroupSelector)).GetGroupKeySelector();
var orderKeySelector = ((IGroupingItemsControlConverterSelector)(parameters.GroupSelector)).GetOrderKeySelector();
if (null == groupKeySelector)
{
throw new NotSupportedException("IGroupingItemsControlConverterSelector.GetGroupSelector must return a non-null value.");
}
// Do the grouping and ordering
var groupedOrderedSequence = sequence.GroupBy(groupKeySelector).OrderBy(orderKeySelector);
// Return the wrapped results
foreach (var group in groupedOrderedSequence)
{
yield return new ContentControl { Content = group.Key, ContentTemplate = parameters.GroupStyle };
foreach (var item in group)
{
yield return new ContentControl { Content = item, ContentTemplate = parameters.ItemStyle };
}
}
}
public object ConvertBack(object value, Type tagetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException("GroupingItemsControlConverter does not support ConvertBack.");
}
}
public class GroupingItemsControlConverterParameters
{
public DataTemplate GroupStyle { get; set; }
public DataTemplate ItemStyle { get; set; }
public IGroupingItemsControlConverterSelector GroupSelector { get; set; }
};
public abstract class IGroupingItemsControlConverterSelector
{
public abstract Func<object, IComparable> GetGroupKeySelector();
public virtual Func<IGrouping<IComparable, object>, IComparable> GetOrderKeySelector() { return g => g.Key; }
}
public class GroupingItemsControlConverterSelector : IGroupingItemsControlConverterSelector
{
public override Func<object, IComparable> GetGroupKeySelector()
{
return (o) => (o as ItemViewModel).Group;
}
}
XAML:
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.Resources>
<DataTemplate x:Key="GroupHeaderTemplate">
<Border BorderBrush="Yellow" BorderThickness="1" Margin="12,3,12,12" Padding="6" VerticalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Number}" HorizontalAlignment="Left" Margin="6,0,0,0" FontSize="22" Foreground="White"/>
<TextBlock Grid.Column="1" Text="{Binding Name}" HorizontalAlignment="Right" Margin="0,0,6,0" FontSize="22" Foreground="White"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="CustomItemTemplate">
<Grid Margin="12,3,12,12" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Grid.Row="0" Text="{Binding Number}" HorizontalAlignment="Left" Margin="6,0,0,0" FontSize="22" Foreground="White"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{Binding Name}" HorizontalAlignment="Right" Margin="0,0,6,0" FontSize="22" Foreground="White"/>
</Grid>
</DataTemplate>
<local:GroupingItemsControlConverter x:Key="GroupingItemsConverter" />
<local:GroupingItemsControlConverterSelector x:Key="GroupingItemsSelector" />
<local:GroupingItemsControlConverterParameters x:Key="GroupingItemParameters"
GroupStyle="{StaticResource GroupHeaderTemplate}"
ItemStyle="{StaticResource CustomItemTemplate}"
GroupSelector="{StaticResource GroupingItemsSelector}"
/>
<Style TargetType="ListBoxItem" x:Key="CustomItemContainerStyle">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</Grid.Resources>
<ListBox x:Name="TheListBox"
ItemsSource="{Binding Items, Converter={StaticResource GroupingItemsConverter}, ConverterParameter={StaticResource GroupingItemParameters}}"
ItemContainerStyle="{StaticResource CustomItemContainerStyle}" />
</Grid>
ListBox grouping? You should consider using the LongListSelector from the Silverlight Toolkit. And to simplify the binding for that, you can use the LongListCollection collection type (Check the entire example, for details).
Then you can simply create apps that groups values, for example like this:

Problem with UpdateSourceTrigger=PropertyChanged and StringFormat in WPF

I have a text box in my application which is data bound to a decimal field in my class and the binding mode is two way. I am using StringFormat={0:c} for currency formatting.
This works fine as long as I don't touch 'UpdateSourceTrigger'. If I set UpdateSourceTrigger=PropertyChanged , It stops formatting the text that I am entering.
here is my code example
Employee.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace Converter
{
public class Employee : INotifyPropertyChanged
{
int _employeeNumber;
string _firstName;
string _lastName;
string _department;
string _title;
decimal _salary;
public Employee()
{
_employeeNumber = 0;
_firstName =
_lastName =
_department =
_title = null;
}
public int EmployeeNumber
{
get { return _employeeNumber; }
set
{
_employeeNumber = value;
OnPropertyChanged("EmployeeNumber");
}
}
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
OnPropertyChanged("FirstName");
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged("LastName");
}
}
public string Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged("Department");
}
}
public string Title
{
get { return _title + " salary: " + _salary.ToString(); }
set
{
_title = value;
OnPropertyChanged("Title");
}
}
public decimal Salary
{
get { return _salary; }
set
{
_salary = value;
OnPropertyChanged("Salary");
OnPropertyChanged("Title");
}
}
public override string ToString()
{
return String.Format("{0} {1} ({2})", FirstName, LastName, EmployeeNumber);
}
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, args);
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}
EmployeeList.cs:
using System.Collections.ObjectModel;
namespace Converter
{
public class EmployeeList : ObservableCollection<Employee>
{
}
}
Window1.xaml:
<Window x:Class="Converter.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Converter"
Title="Window1" Height="500" Width="500">
<Window.Resources>
<local:EmployeeList x:Key="myEmployeeList">
<local:Employee EmployeeNumber="1" FirstName="John" LastName="Dow" Title="Accountant" Department="Payroll" Salary="25000.00" />
<local:Employee EmployeeNumber="2" FirstName="Jane" LastName="Austin" Title="Account Executive" Department="Customer Management" Salary="25000.00" />
<local:Employee EmployeeNumber="3" FirstName="Ralph" LastName="Emmerson" Title="QA Manager" Department="Product Development" Salary="25000.00" />
<local:Employee EmployeeNumber="4" FirstName="Patrick" LastName="Fitzgerald" Title="QA Manager" Department="Product Development" Salary="25000.00" />
<local:Employee EmployeeNumber="5" FirstName="Charles" LastName="Dickens" Title="QA Manager" Department="Product Development" Salary="25000.00" />
</local:EmployeeList>
<local:StringToDecimalCurrencyConverter x:Key="StringToDecimalCurrencyConverter"></local:StringToDecimalCurrencyConverter>
</Window.Resources>
<Grid DataContext="{StaticResource myEmployeeList}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="240" />
<RowDefinition Height="45" />
</Grid.RowDefinitions>
<ListBox Name="employeeListBox" ItemsSource="{Binding Path=., Mode=TwoWay}" Grid.Row="0" />
<Grid Grid.Row="1" DataContext="{Binding ElementName=employeeListBox, Path=SelectedItem, Mode=TwoWay}">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0">First Name</Label>
<Label Grid.Row="1" Grid.Column="0">Last Name</Label>
<Label Grid.Row="2" Grid.Column="0">Title</Label>
<Label Grid.Row="3" Grid.Column="0">Department</Label>
<Label Grid.Row="4" Grid.Column="0">Salary</Label>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=FirstName}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=LastName}" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=Title}" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Mode=TwoWay, Path=Department}" />
<TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Mode=TwoWay, StringFormat=\{0:c\}, UpdateSourceTrigger=PropertyChanged, Path=Salary}" />
<TextBlock Grid.Row="5" Grid.Column="1" Text="{Binding Mode=OneWay, Converter={StaticResource StringToDecimalCurrencyConverter}, Path=Salary}" />
</Grid>
</Grid>
</Window>
If you remove 'UpdateSourceTrigger=PropertyChanged' from the above code it works fine.
I have also tried using Converter instead of the StringFormat, and still the problem is not solved.
The problem is that if you use a converter and update on property changed then WPF will ignore property changes while it is the process of updating the source property. Since the PropertyChanged event is raised from the setter, WPF ignores it.
The reason it does this is that if you typed "1" in the text box, this would get converted to the decimal value 1.0 and then get converted back to the string "$1.00". This would change the text in the text box and reset the cursor, so if you tried to type "12" you'd end up with "2$1.00".
Note that your Employee object is getting updated, and the problem is just that the TextBox isn't getting a newly formatted value.
If you really do want that behavior, you can set IsAsync=True on the binding and WPF will no longer see it as a reentrant change and will allow it. This has also changed in .NET 4.0, so if you upgrade to the latest version of the framework then you should see the behavior you expect.

Resources