silver light datagrid - silverlight

Iam new to silverlight so i need help from your side. my query is one page haivng the datagrid,that datagrid have only 6 columns.after 6 columns their is a scape so that scape showing itself one column.so i avoid that column in datagrid.scape may be show with out the column this is my query.
it is urgent for me.please resolve the solution as possible as early.

While I have no idea what a 'scape' is, what you need to do is start out by creating a 'display' class that inherits from IEditable and INotify. For example:
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Application.Views.DisplayClasses
{
public class DisplayClass : IEditableObject, INotifyPropertyChanged
{
//Create private vars
private string a;
private string b;
private string c;
private string d;
private bool e;
// Create public properties with meta data to tell the grid to display and what order etc
[Display(AutoGenerateField = false)]
public string A
{
get { return a; }
set { a = value; }
}
[Display(Order = 0, Name = "B", AutoGenerateField = true)]
public string B
{
get { return b; }
set { b = value; }
}
[Display(Order = 1, Name = "C", AutoGenerateField = true)]
public String C
{
get { return c; }
set { c= value; }
}
[Display(Order = 2, Name = "D", AutoGenerateField = true)]
public string D
{
get { return d; }
set { d = value; }
}
[Display(Order = 2, Name = "E", AutoGenerateField = true)]
public string E
{
get { return e; }
set { e = value; }
}
#region IEditableObject Members
public void BeginEdit()
{
}
public void CancelEdit()
{
}
public void EndEdit()
{
}
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null))
{
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
}
Then you need to create an ObservableCollection to store the data your getting back from the database in:
// Code to get data from the database (from your webservice)
//Make this Observable collection global
public static ObservableCollection<DisplayClass> ItemList = new ObservableCollection<DisplayClass>();
// In your oncompleted event method, put something similar to the following code
foreach (var DatabaseItem in DataFromMyWebService)
{
DisplayClass GridItem = new DisplayClass();
GridItem.A = DatabaseItem.A;
GridItem.B = DatabaseItem.B;
GridItem.C = DatabaseItem.C;
GridItem.D = DatabaseItem.D;
ItemList.Add(GridItem);
}
dgDataGrid.ItemsSource = ItemList;
You want to make your observable collection global so that if you need to change an item in your collection, the datagrid will automatically display those changes. Notice the meta data ([]) in the display class. That is how you control which properties are displayed and in what order. You will also want to set the property 'AutoGenerate="True"' in your datagrid element in your XAML code.

Related

How to Bind Checked / Selected Items From CheckListBox in WPF by using MVVM Model (I am using "WPFToolkit.Extended.dll" to get CheckListBox Control)

CheckList Box from WPFToolKit. Below is XAML code (MainWindow.xaml)
<xctk:CheckListBox x:Name="SiteCheckList" Margin="0,0,512,0" Height="100" Width="150"
ItemsSource="{Binding SiteList}"
DisplayMemberPath="SiteName"
CheckedMemberPath="IsChecked">
</xctk:CheckListBox>
Below Properties added in Model Class. I would like to get Checked Items from CheckListBox to my string List (Model.cs).
This string List I will be using for further in project logic.
private string _SiteName;
public string SiteName
{
get { return _SiteName; }
set { _SiteName = value; }
}
private List<string> _SelectedSiteList;
public List<string> SelectedSiteList
{
get { return _SelectedSiteList; }
set
{
_SelectedSiteList = value;
}
}
View Model (ViewModel.cs)
class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Model> _SiteList;
public ObservableCollection<DataModel> SiteList
{
get { return _SiteList; }
set { _SiteList = value; }
}
public ViewModel()
{
SiteList = new ObservableCollection<Model>();
PoppulateSiteNames();
}
private void PoppulateSiteNames()
{
Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
keyValuePairs = Files.ReadIni_KeyValue("SiteSection");
foreach (string Key in keyValuePairs.Keys)
{
keyValuePairs.TryGetValue(Key, out string LogTable);
SiteList.Add(new Model() { SiteName = LogTable });
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string PropertyName)
{
if (PropertyChanged !=null)
{
PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
Here I would like to get list of Checked / Selected Items from UI. If I don't want to write any code in MainWindow.cs i.e. CheckedChanged event then How I can do it by using Binding method ?
Updated Model Class with IsChecked Boolean Property.
private bool _IsChecked;
public bool IsChecked
{
get { return _IsChecked; }
set { _IsChecked = value; }
}
Then ViewModel Updated with Below Function to Populate SiteList
private void PoppulateSiteNames()
{
Dictionary<string, string> keyValuePairs = Files.ReadIni_KeyValue(Vars.MSSQL_Section);
string [] Sites = keyValuePairs.Values.ToArray();
for (int i = 0; i < Sites.Length; i++)
{
SiteList.Add(new HistoricalDataModel { SiteName = Sites[i] });
}
}
Now, Finally I got CheckedItems in below Variable using LINQ
var checkedSites = from site in SiteList
where (site.IsChecked == true)
select new { site.SiteName };
Thank you all of you for responding my question and triggering me to think more.

Exposing custom properties using UI Automation Framework

Given a very basic WinForms custom/user control, using System.Windows.Automation it is possible to manipulate built in properties for the custom control.
This is done like this:
public object GetPropertyValue(int propertyId)
{
if (propertyId == AutomationElementIdentifiers.NameProperty.Id)
{
return "Hello World!";
}
}
What I would like to do is expose custom properties to ui automation such as ReadyState, LastAccessed, Etc.
Is this possible?
No, you can't extend the list of properties, and this is complicated by the fact you use Winforms that has a poor UI Automation support (it uses IAccessible with bridges etc.).
What you can do though is add some fake objects to the automation tree, for example, here is a sample Winforms UserControl that does it:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
Button button = new Button();
button.Location = new Point(32, 28);
button.Size = new Size(75, 23);
button.Text = "MyButton";
Controls.Add(button);
Label label = new Label();
label.Location = new Point(49, 80);
label.Size = new Size(35, 13);
label.Text = "MyLabel";
Controls.Add(label);
MyCustomProp = "MyCustomValue";
}
public string MyCustomProp { get; set; }
protected override AccessibleObject CreateAccessibilityInstance()
{
return new UserControl1AccessibleObject(this);
}
protected class UserControl1AccessibleObject : ControlAccessibleObject
{
public UserControl1AccessibleObject(UserControl1 ownerControl)
: base(ownerControl)
{
}
public new UserControl1 Owner
{
get
{
return (UserControl1)base.Owner;
}
}
public override int GetChildCount()
{
return 1;
}
public override AccessibleObject GetChild(int index)
{
if (index == 0)
return new ValueAccessibleObject("MyCustomProp", Owner.MyCustomProp);
return base.GetChild(index);
}
}
}
public class ValueAccessibleObject : AccessibleObject
{
private string _name;
private string _value;
public ValueAccessibleObject(string name, string value)
{
_name = name;
_value = value;
}
public override AccessibleRole Role
{
get
{
return AccessibleRole.Text; // activate Value pattern
}
}
// note you need to override with member values, base value cannot always store something
public override string Value { get { return _value; } set { _value = value; } }
public override string Name { get { return _name; } }
}
And this is how it appears in the automation tree (using the inspect.exe tool):
Note this technique also supports writing back to the property because it's based on the ValuePattern.

Databinding a WinForms ComboBox requires user-interaction twice

I have a ComboBox (DropDownList style) in a Windows Form which has a data-source set to a BindingList, and has the SelectedValue property bound to a viewmodel's property.
Note that the binding is set to OnPropertyChanged rather than OnValidate, this is because when using OnValidate the control will not necessarily update the ViewModel if the form is closed or loses focus (but the control still thinks it has focus. On the Compact Framework there is no way to 'force validation' so I have to use OnPropertyChanged.
There's a problem which is reproducible on both desktop Windows Forms and Smart Device Windows Forms: when attempting to select or set the current item in the combobox (using the mouse or keyboard) the value will not "stick" until it is set twice - that is, you need to select the same item twice before the combobox's value will change.
There are no exceptions thrown (even caught exceptions) and no diagnostics reports to speak of.
I don't think this is a bug in the framework, and it's interesting how it happens on both Desktop and Compact Framework.
Here's my code:
Form1.cs
public partial class Form1 : Form {
private ViewModel _vm;
public Form1() {
InitializeComponent();
this.bindingSource1.Add( _vm = new ViewModel() );
}
}
Form1.Designer.cs (relevant lines)
//
// bindingSource1
//
this.bindingSource1.DataSource = typeof( WinForms.Shared.ViewModel );
//
// comboBox1
//
this.comboBox1.DataBindings.Add( new System.Windows.Forms.Binding( "SelectedValue", this.bindingSource1, "SelectedSomeTypeId", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged ) );
this.comboBox1.DataSource = this.someTypeListBindingSource;
this.comboBox1.DisplayMember = "DisplayText";
this.comboBox1.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBox1.FormattingEnabled = true;
this.comboBox1.Location = new System.Drawing.Point( 12, 27 );
this.comboBox1.Name = "comboBox1";
this.comboBox1.Size = new System.Drawing.Size( 182, 21 );
this.comboBox1.TabIndex = 0;
this.comboBox1.ValueMember = "Id";
//
// someTypeListBindingSource
//
this.someTypeListBindingSource.DataMember = "SomeTypeList";
this.someTypeListBindingSource.DataSource = this.bindingSource1;
ViewModel.cs
public class ViewModel : INotifyPropertyChanged {
public ViewModel() {
this.SomeTypeList = new BindingList<SomeType>();
for(int i=0;i<5;i++) {
this.SomeTypeList.Add( new SomeType() {
Id = i + 1,
Name = "Foo" + ((Char)( 'a' + i )).ToString()
} );
}
this.SelectedSomeTypeId = 2;
}
public BindingList<SomeType> SomeTypeList { get; private set; }
private Int64 _selectedSomeTypeId;
public Int64 SelectedSomeTypeId {
get { return _selectedSomeTypeId; }
set {
if( _selectedSomeTypeId != value ) {
_selectedSomeTypeId = value;
OnPropertyChanged("SelectedSomeTypeId");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String propertyName) {
PropertyChangedEventHandler handler = this.PropertyChanged;
if( handler != null ) handler( this, new PropertyChangedEventArgs(propertyName) );
}
}
public class SomeType {
public String Name { get; set; }
public Int64 Id { get; set; }
public String DisplayText {
get { return String.Format("{0} - {1}", this.Id, this.Name ); }
}
}
I have never found the 'right' way around this issue and generally use one of two ways to make things work:
Direct: Just bypass the binding mechanism for this one entry
combo1.SelectedIndexChanged += (s,e) _viewModel.Item = combo1.SelectedItem;
Generic Binding: Make a custom ComboBox and override the OnSelectedIndexChanged event to force the binding update.
public class BoundComboBox : ComboBox
{
protected override void OnSelectedIndexChanged(EventArgs e)
{
var binding = this.DataBindings["SelectedItem"];
if( binding != null )
binding.WriteValue();
base.OnSelectedIndexChanged(e);
}
}

Validation firing too early

I have built a base class for my view model(s). Here is some of the code:
public class BaseViewModel<TModel> : DependencyObject, INotifyPropertyChanged, IDisposable, IBaseViewModel<TModel>, IDataErrorInfo
{
public TModel Model { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (this._disposed)
{
return;
}
if (disposing)
{
this.Model = default(TModel);
}
this._disposed = true;
}
}
Okay, so I thought, let's add some validation to the base class, which led me to the following article: Prism IDataErrorInfo validation with DataAnnotation on ViewModel Entities. So I added the following methods / properties (IDataErrorInfo) to my base class:
string IDataErrorInfo.Error
{
get { return null; }
}
string IDataErrorInfo.this[string columnName]
{
get { return ValidateProperty(columnName); }
}
protected virtual string ValidateProperty(string columnName)
{
// get cached property accessors
var propertyGetters = GetPropertyGetterLookups(GetType());
if (propertyGetters.ContainsKey(columnName))
{
// read value of given property
var value = propertyGetters[columnName](this);
// run validation
var results = new List<ValidationResult>();
var vc = new ValidationContext(this, null, null) { MemberName = columnName };
Validator.TryValidateProperty(value, vc, results);
// transpose results
var errors = Array.ConvertAll(results.ToArray(), o => o.ErrorMessage);
return string.Join(Environment.NewLine, errors);
}
return string.Empty;
}
private static Dictionary<string, Func<object, object>> GetPropertyGetterLookups(Type objType)
{
var key = objType.FullName ?? "";
if (!PropertyLookupCache.ContainsKey(key))
{
var o = objType.GetProperties()
.Where(p => GetValidations(p).Length != 0)
.ToDictionary(p => p.Name, CreatePropertyGetter);
PropertyLookupCache[key] = o;
return o;
}
return (Dictionary<string, Func<object, object>>)PropertyLookupCache[key];
}
private static Func<object, object> CreatePropertyGetter(PropertyInfo propertyInfo)
{
var instanceParameter = System.Linq.Expressions.Expression.Parameter(typeof(object), "instance");
var expression = System.Linq.Expressions.Expression.Lambda<Func<object, object>>(
System.Linq.Expressions.Expression.ConvertChecked(
System.Linq.Expressions.Expression.MakeMemberAccess(
System.Linq.Expressions.Expression.ConvertChecked(instanceParameter, propertyInfo.DeclaringType),
propertyInfo),
typeof(object)),
instanceParameter);
var compiledExpression = expression.Compile();
return compiledExpression;
}
private static ValidationAttribute[] GetValidations(PropertyInfo property)
{
return (ValidationAttribute[])property.GetCustomAttributes(typeof(ValidationAttribute), true);
}
Okay, this brings me to the issue. The thing is the validation works perfectly, but lets say I have a property (within my view model called: Person) with a StringLength attribute. The StringLength attribute fires as soon as the application is opened. The user didn't even have a chance to do anything. The validation fires as soon as the application is started.
public class PersonViewModel : BaseViewModel<BaseProxyWrapper<PosServiceClient>>
{
private string _password = string.Empty;
[StringLength(10, MinimumLength = 3, ErrorMessage = "Password must be between 3 and 10 characters long")]
public string Password
{
get { return this._password; }
set
{
if (this._password != value)
{
this._password = value;
this.OnPropertyChanged("Password");
}
}
}
}
I have noticed that this is caused by the IDataErrorInfo.this[string columnName] property, and in turn it calls the ValidateProperty method. But, I have no idea how to fix this?
There could be two issues...
Do you populate yopur Person instance by using the public properties?
e.g.
new Person { Password = null }
This will fire the property changed notification for Password and will validate it.
Some developers also set the properties in constructors...
public class Person {
public Person() {
this.Password = null;
}
}
Recommended practise is to use private fields...
public class Person {
public Person() {
_password = null;
}
public Person(string pwd) {
_password = pwd;
}
}
OR
You can create a flag in our view model base say IsLoaded. Make sure you set it to true only after your UI is loaded (probably in UI.Loaded event). In your IDataErrorInfo.this[string columnName] check if this property is true and only then validate the values. Otherwise return null.
[EDIT]
The following change did the job:
public class PersonViewModel : BaseViewModel<BaseProxyWrapper<PosServiceClient>>
{
private string _password;
[StringLength(10, MinimumLength = 3, ErrorMessage = "Password must be between 3 and 10 characters long")]
public string Password
{
get { return this._password; }
set
{
if (this._password != value)
{
this._password = value;
this.OnPropertyChanged("Password");
}
}
}
public PersonViewModel(BaseProxyWrapper<PosServiceClient> model)
: base(model)
{
this._username = null;
}
}
Something I've done in the past is change the update source trigger to explicit, create a behavior that will update the source when the TextBox loses focus, and then attach that behavior to the TextBox.

INotifyPropertyChanged PropertyChangedEventHandler event is always null

I am trying to get my hands on WPF, and I have encountered a small problem when updating, mainly that I am getting the old data displayed while the new data is correctly updated in the XML file. I have implemented INotifyPropertyChanged as follows :-
public class Products : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _prodId;
public string ProdID
{
get { return _prodId; }
set
{
_prodId = value;
OnPropertyChanged("ProdID");
}
}
private string _prodName;
public string ProdName
{
get { return _prodName; }
set
{
_prodName = value;
OnPropertyChanged("ProdName");
}
}
private string _prodPrice;
public string ProdPrice
{
get { return _prodPrice; }
set
{
_prodPrice = value;
OnPropertyChanged("ProdPrice");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
and then the update is as follows :-
foreach (XmlNode node in nodeList)
{
if (nodeList[i].ChildNodes[0].InnerText == strID)
{
Products products = new Products();
products.ProdName = strName;
products.ProdPrice = strPrice;
nodeList[i].ChildNodes[1].InnerText = strName;
nodeList[i].ChildNodes[2].InnerText = strPrice;
break;
}
i++;
}
The XML is being saved correctly with the new ProdName and Price, however when I display the listView after the update, i am still getting the wrong values.
I am binding the Products like this:-
public static List<Products> LoadProduct()
{
string fileName = "Products.xml";
List<Products> ListProdRecords = new List<Products>();
// Execute the query using the LINQ to XML
var prods = from p in XElement.Load(fileName).Elements("Product") select p;
foreach (var product in prods)
{
Products lProduct = new Products
{
ProdID = product.Element("ProductId").Value,
ProdName = product.Element("ProductName").Value,
ProdPrice = product.Element("Price").Value
};
ListProdRecords.Add(lProduct);
}
return ListProdRecords.ToList();
}
here is the binding code :-
private void LoadProducts()
{
List<Products> productList = new List<Products>();
productList = ProductDAL.LoadProduct();
listView1.DataContext = productList;
}
public static void UpdateProduct(string strID, string strName, string strPrice)
{
string fileName = "Products.xml";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(fileName);
XmlNodeList nodeList = xmlDoc.SelectNodes("/Products/Product");
int i = 0;
foreach (XmlNode node in nodeList)
{
if (nodeList[i].ChildNodes[0].InnerText == strID)
{
Products products = new Products();
products.ProdName = strName;
products.ProdPrice = strPrice;
nodeList[i].ChildNodes[1].InnerText = strName;
nodeList[i].ChildNodes[2].InnerText = strPrice;
break;
}
i++;
}
Any help on what's wrong?
Thanks for your help and time
I don't really see, what the newly created products in your loop have to do with a listView. You don't add them to a list or add them to the listView in another way.
Or in other words: The creation of those instances inside your loop is completely useless and will be removed by the optimizer.
You need to update the instances of the Products class that are in the list you bound to the listView.

Resources