data grid binding in silverlight - silverlight

I have a simple class abc
class abc
{
public string a { get; set; }
public string b { get; set; }
public string c { get; set; }
public abc(string d, string e, string f)
{
a = d;
b = e;
c = f;
}
}
public MainPage()
{
InitializeComponent();
abc obj = new abc("abc1", "abc2", "abc3");
LayoutRoot.DataContext = obj;
}
and a grid which contain three textbox 1 2 3 I am trying to bind these 3 properties of a class to a grid usercontrol.
<Grid x:Name="LayoutRoot" Background="White">
<TextBox Height="27" HorizontalAlignment="Left" Margin="125,86,0,0" Name="textBox1" Text="{Binding Path= a}" VerticalAlignment="Top" Width="120" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="21,192,0,83" Name="textBox2" Text="{Binding Path= b}" Width="120" />
<TextBox Height="25" HorizontalAlignment="Left" Margin="250,192,0,0" Name="textBox3" Text="{Binding Path= c}" VerticalAlignment="Top" Width="120" />
</Grid>
it doesn't show any error but it does not show any output to a screen,what specific problem it creating?

Try do not use "Path= " (with space) in the binding expression. Try use:
Text="{Binding a}"
"Path" is present hiddenly in binding expressions. You need read some resources about bindings.

First your type 'abc' should implement INotifyPropertyChanged.
public class abc : INotifyPropertyChanged
{
...
}
Then you need to raise the INotifyPropertyChanged.PropertyChanged event
private void RaiseProperty(string propertyName)
{
var handle = PropertyChanged;
if(handle != null)
{
handle(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _a;
public string a { get{ return _a;} set{ _a = value; RaiseProperty("a"); } }
....
This should work as you need to a mechanism to notify the Binding if you are using CLR proprties; and that mechanism is provided by INotifyPropertyChanged interface

Related

WPF TextBox Binding ElementName null?

I have a ListBox control with TypeUsers.When I select some record in Listbox and update Name in TextBox the Name property/textbox return always null. Never take value from TextBox, always null ?
Image description here
This is my code
<ListBox x:Name="LstTypeUsers"
Grid.Row="0" Grid.Column="4"
Width="220" Height="120"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding TypeUsers}"
DisplayMemberPath="Name">
</ListBox>
<TextBox
Grid.Row="0" Grid.Column="2"
x:Name="txtName"
HorizontalAlignment="Left" Height="23"
TextWrapping="Wrap"
VerticalAlignment="Top" Width="170"
Text="{Binding ElementName=LstTypeUsers, Path=SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"
Validation.ErrorTemplate="{x:Null}"/>
<Button
Grid.Column="0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="100" Height="30"
Command="{Binding UpdateTypeUserCmd}"
Grid.ColumnSpan="3" Margin="20,90,0,0">
<StackPanel Orientation="Horizontal">
<Image Source="/Images/Save.png" />
<TextBlock Width="55" Height="18" ><Run Text=" "/><Run Text="Update"/></TextBlock>
</StackPanel>
</Button>
EDIT
// Model class
public class UserType: INotifyPropertyChanged
{
[Key]
private int usertypeId;
public int UserTypeId
{
get
{
return this.usertypeId;
}
set
{
this.usertypeId = value;
OnPropertyChanged("UserTypeId");
}
}
[MaxLength(200)]
private string name;
public string Name
{
get
{
return this.name;
}
set
{
this.name = value;
OnPropertyChanged("Name");
}
}
[Required]
private bool status;
public bool Status
{
get
{
return this.status;
}
set
{
this.status = value;
OnPropertyChanged("Status");
}
}
public virtual ObservableCollection<User> User { get; private set; }
public UserType()
{
this.User = new ObservableCollection<User>();
}
}
// ViewModelBase class
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// UserTypeViewModel
public class UserTypeViewModel
private UserType _userType;
private ObservableCollection<UserType> _UserTypeList;
// Constructor
public UserTypeViewModel()
{
_userType = new UserType();
_UserTypeList = new ObservableCollection<UserType>(GetUserTypeAll());
}
public ObservableCollection<TypeUsers> TypeUsers
{
get
{
return _UserTypeList;
}
set
{
_UserTypeList = value;
//OnPropertyChanged("TypeUsers");
}
}
public string Name
{
get
{
return _userType.Name;
}
set
{
_userType.Name = value;
//OnPropertyChanged("Name");
}
}
Thank you.
Implement INotifyPropertyChanged interface in UserType class.
You're binding directly to the WPF control (ListBox) and not the ViewModel. I suggest you add a property in your ViewModel that will bind to the TextBox.Text property, once the data changes or the user had changed the value in the TextBox, then the data will update and be reflected in the UI.
Also, if I remember correctly, at launch, the SelectedItem property of the ListBox is null, so there might be a problem there too, but I'm not certain about that...
I have resolved my problem. I have also implemented INotifyPropertyChanged interface in Model class. I'm new in WPF MVVM and I read that this interface is implemented only in the ViewModel for connection with View. Now I have implemented in both classes and everything works great.
Thanks Everyone.

WPF listbox binding to List<string> or List<string[]>

I'm very new to WPF (especially XAML) *
Hello, my app has a class which gets bunch of comma separated string. So I made a List collection to store the strings. Also, I made DataTemplate for the listbox. Here is code.
MainWindow.xaml
...
<DataTemplate x:Key="DataTemplate">
<Grid>
<StackPanel Grid.Column="1" Margin="5">
<StackPanel Orientation="Horizontal" TextBlock.FontWeight="Bold" >
<TextBlock Text="{Binding AAA}" />
</StackPanel>
<TextBlock Text="{Binding BBB}" />
<TextBlock Text="{Binding CCC}" />
</StackPanel>
</Grid>
</DataTemplate>
...
<ListBox x:Name="listbox1" HorizontalAlignment="Left" Height="309" Margin="10,10,0,0" Width="216" BorderThickness="1" VerticalAlignment="Top" ItemTemplate="{DynamicResource HeadlineDataTemplate}"/>
MainWindow.xaml.cs
...
MyClass myClass;
public MainWindow()
{
InitializeComponent();
myClass = new MyClass();
}
...
private void Button_Click(object sender, RoutedEventArgs e)
{
myClass.getData(Textbox1.Text); // I want to convert this to add items to listbox1.
}
MyClass.cs
...
public void getData(string target)
{
List<string> itemList = new List<string>();
...
while(result != null)
{
// This loop gives bunch of comma separated string (more than 100)
itemList.Add(result);
}
// after the loop, itemList has
// itemList[0] = {"AAA1,BBB1,CCC1"}
// itemList[1] = {"AAA2,BBB2,CCC2"}
// itemList[2] = {"AAA3,BBB3,CCC3"}
// ...
// I also can store the strings to List<string[]> using string.split().
}
So how should I do this?
I couldn't find the answer on the internet.
I suggest to create a model class to represent each ListBox Item. In this example I name it MyListBoxItemModel :
public class MyListBoxItemModel
{
public string AAA { get; set; }
public string BBB { get; set; }
public string CCC { get; set; }
}
Then in the getData function, create List of MyListBoxItemModel to be listbox1's ItemsSource :
public void getData(string target)
{
List<MyListBoxItemModel> itemList = new List<MyListBoxItemModel>();
...
while(result != null)
{
var splittedResult = result.Split(',');
itemList.Add(new MyListBoxItemModel{
AAA = splittedResult[0],
BBB = splittedResult[1],
CCC = splittedResult[2]
});
}
listbox1.ItemsSource = itemList;
}
Note that this example only demonstrates minimum amount of code needed to get your data displayed in the ListBox. Not involving various techniques and best practices around WPF development, such as implementing INotifyPropertyChanged interface, MVVM pattern, etc.
you can just bind to public properties, so if you write something like
<TextBlock Text="{Binding BBB}" />
you need an object with a public property "BBB".
so in addition to the answer from har07 you should also use a public property for your list(OberservableCollection)
public OberservableCollection<MyListBoxItemModel> ItemList {get;set;}
then your binding for your itemscontrol can look like this
<ListBox ItemsSource="{Binding ItemList}" ItemTemplate="{DynamicResource HeadlineDataTemplate}"/>
all you need now is the right datacontext ;)

WPF IDataErrorInfo process error array

I´m using IDataErrorInfo for validation in WPF, But when the attribute is an array I can to process the error. ( in this case int[] Position)
My code is similar to this: http://codeblitz.wordpress.com/2009/05/08/wpf-validation-made-easy-with-idataerrorinfo/
public class Customer : IDataErrorInfo
{
public string FirstName { get; set; }
public int[] Position { get; set; }
#region IDataErrorInfo Members
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columName == "FirstName")
{
// Do something
}
if (columnName == "Position")
{
// Do something
}
return result;
}
}
#endregion
}
XAML
<TextBox x:Name="tbFirstName" Grid.Row="2" Grid.Column="1" Width="50" HorizontalAlignment="left"
Validation.Error="Validation_Error" MaxLength="2"
Text="{Binding UpdateSourceTrigger=PropertyChanged,
Path=FirstName, ValidatesOnDataErrors=true, NotifyOnValidationError=true}" />
<TextBox x:Name="tbPosition1" Grid.Row="2" Grid.Column="1" Width="50" HorizontalAlignment="left"
Validation.Error="Validation_Error" MaxLength="2"
Text="{Binding UpdateSourceTrigger=PropertyChanged,
Path=Position[0], ValidatesOnDataErrors=true, NotifyOnValidationError=true}" />
I have no problem to capture "Firstname" but if I do a change in the textbox of btPosition1 the program don´t through the function to process the errors.
You bind to an item in array, not to array itself.
In this case, I think, WPF looks for IDataErrorInfo in Array class.
So you should either expose positions as separate properties (if they are finite), or use your own collection class: inherit List<> and add IDataErrorInfo implementation.

Listbox not updating when items added or removed from ObservableCollection

I have a "Hello World" type application.
A listbox.ItemsSource = Players. Players is an ObservableCollection of Player that implements INotifyPropertyChanged.
When I add items in the Players constructor the items are displayed fine.
When I update an existing item the changes are reflected.
But when I add or remove items for the ObserveableCollection the listbox does not reflect the Items added / removed.
xaml in MainPage:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox Name="lstPlayers" ItemsSource="{Binding}" Margin="12,66,13,24" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<!--<StackPanel Background="#FFD1D1D1">-->
<Grid Margin="0,0,0,0" Grid.RowSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Number}" FontSize="48" />
<TextBlock Grid.Column="1" Text="{Binding Name}" FontSize="48" />
</Grid>
<!--</StackPanel>-->
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Button" Height="95" HorizontalAlignment="Left" Margin="183,350,0,0" Name="button1" VerticalAlignment="Top" Width="260" Click="button1_Click" />
<Button Content="Button" Height="72" HorizontalAlignment="Left" Margin="198,472,0,0" Name="button3" VerticalAlignment="Top" Width="232" Click="button3_Click" />
</Grid>
The listbox is bound in the code behind:
lstPlayers.ItemsSource = plys;
Player Class:
using System.ComponentModel;
namespace DatabindList
{
public class TcrPlayer : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
_name = value;
NotifyPropertyChanged("Name");
}
}
}
}
Players class:
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace DatabindList
{
public class TcrPlayers : List<TcrPlayer>
{
public ObservableCollection<TcrPlayers> Items { get; private set; }
public TcrPlayers()
{
//these are displayed
Add(new TcrPlayer { Name = "Christine"});
Add(new TcrPlayer { Name = "Janet"});
Add(new TcrPlayer { Name = "Ian"});
}
public void AddPlayer()
{
//THIS HAS NO EFFECT ON THE LISTBOX
Add(new TcrPlayer { Name = "Newbie", Number = "99" });
}
}
}
I can UPDATE an existing item in the list by using the code behind in the MainPage with
var itm = lstPlayers.SelectedItem as TcrPlayer;
itm.Name = "Fred";
but I can't reflect any changes made to the number of items in the Players collection.
TcrPlayers derives from List<TcrPlayer> and adds items to itself. However, the ObservableCollection<TcrPlayer> property isn't connected to that list in any way whatsoever. Assuming that plys is a TcrPlayers you're not binding to an ObservableCollection at all - you're binding to a non-observable List.
Inheriting from ObservableCollection<TcrPlayer> instead of List<TcrPlayer> and removing the unused property might get you closer to where you want to be.
As an aside, you don't see this pattern used very often because inheriting from a collection class isn't generally considered very useful unless you're adding new functionality. Usually you'd just have an ObservableCollection<TcrPlayer> property of the parent viewmodel and bind the listbox's ItemsSource to that.
Speaking of which, you're also setting ItemsSource twice - in your XAML to {Binding} i.e. the current DataContext, and in the codebehind.
You don't use your ObservableCollection. Instead your TcrPlayers class is a list itself (derives from List<T>).
Either derive from ObservableCollection and remove your Items Property or use Items.Add(..) instead of Add().
E.g.
public class TcrPlayers : ObservableCollection<TcrPlayer>
{
..
or
public class TcrPlayers
{
public ObservableCollection<TcrPlayers> Items { get; private set; }
public TcrPlayers()
{
//these are displayed
Items.Add(new TcrPlayer { Name = "Christine"});
Items.Add(new TcrPlayer { Name = "Janet"});
Items.Add(new TcrPlayer { Name = "Ian"});
}

Problem showing selected value of combobox when it is bind to a List<T> using Linq to Entities

I have a ComboBox which is has an ItemTemplate applied on it and is bind to a List of entity return using linq. I'm using mvvm. It is bind to it successfully but when I set the selected value of it from code at runtime to show the selected value coming from db it doesn't select it. For reference here is my ComboBox xaml.
<DataTemplate x:Key="ManufacturerDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image x:Name="imgManufacturer" Width="25" Height="25"
Source="{Binding Path=ManufacturerImage}" Grid.Column="0"/>
<TextBlock x:Name="txtManufacturer" Grid.Column="1" HorizontalAlignment="Left"
VerticalAlignment="Center" Text="{Binding Path=ManufacturerName}"
Tag="{Binding Path=ManufacturerID}"/>
</Grid>
</DataTemplate>
<ComboBox x:Name="cboManufacturer"
SelectionChanged="cboManufacturer_SelectionChanged"
ItemsSource = "{Binding Path=CurrentManufacturers}"
SelectedValue="{Binding Path=SelectedManufacturer}"
Grid.Column="3" Grid.Row="2" Margin="20,9.25,68,7.75"
ItemTemplate="{StaticResource ManufacturerDataTemplate}" TabIndex="6"/>
Here is my part from code behind from viewModel.
List<tblManufacturer> currentManufacturers
= new List<tblManufacturer>();
tblManufacturer selectedManufacturer = null;
public List<tblManufacturer> CurrentManufacturers
{
get
{
return currentManufacturers;
}
set
{
currentManufacturers = value;
NotifyPropertyChanged("CurrentManufacturers");
}
}
public tblManufacturer SelectedManufacturer
{
get
{
return selectedManufacturer;
}
set
{
selectedManufacturer = currentManufacturers.Where(mm => mm.ManufacturerID == Convert.ToInt32(selectedDevice.tblManufacturer.EntityKey.EntityKeyValues[0].Value)).First();
NotifyPropertyChanged("SelectedManufacturer");
}
}
Here is the sample code snippet:
Xaml for ComboBox:
<ComboBox ItemsSource="{Binding ManufacturerList}" DisplayMemberPath="Name" SelectedValuePath="ID"
SelectedItem="{Binding SelectedManufacturer}"/>
ViewModel code :
public class Manufacturer
{
public int ID { get; set; }
public string Name { get; set; }
}
private List<Manufacturer> _manufactuerlist;
private Manufacturer _selectedManufacturer;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public Manufacturer SelectedManufacturer
{
get
{
return _selectedManufacturer;
}
set
{
_selectedManufacturer = value;
NotifyPropertyChanged("SelectedManufacturer");
}
}
public List<Manufacturer> ManufacturerList
{
get
{
return _manufactuerlist;
}
set
{
_manufactuerlist = value;
NotifyPropertyChanged("ManufacturerList");
}
}
And finally Set the Selected Manufacturer in your view model like this:
SelectedManufacturer = _manufactuerlist.Find(m => m.ID == 2);

Resources