I have a Common Field Object:
public class Field
{
public string Name { get; set; }
public string oldName { get; set; }
private object _Value = null;
public object Value
{
get
{
return _Value;
}
set
{
_Value = value;
}
}
private FieldType _fieldType = FieldType.Normal;
public FieldType FieldType
{
get
{
return _fieldType;
}
set
{
_fieldType = value;
}
}
private bool _isKey = false;
public bool IsKey
{
get
{
return _isKey;
}
set
{
_isKey = value;
}
}
}
a Common Record Object:
public class Record
{
public string TableName{get;set;}
pubilc FieldCollection _fieldcollection = new FieldCollection();
public FieldCollection FieldCollection
{
get
{
return _fieldcollection;
}
set
{
_fieldcollection = value;
}
}
}
The Data from database to convert to Record Object,and then I want to Binding the Record Data to the Control,but it's not working.
I want to know how can I Binding Data like:
textBox1.DataBindings.Add("Text", listBox1.DataSource , "BarDesc");
I think you want to drag and drop a BindingSource control onto your winform in Design-Time.
Set the BindingSource's DataSource property > Object > Record class. Then set the BindingSource's DataMember.
Select your control (eg Textbox) and set its DataBinding property to the bindingSource control's DataMember.
HTH, at least it should point you in the right direction.
Related
I want to ask exactly the same question that was asked in this link and also a person answered too but I couldn't understand how to incorporate that in the code. Sorry for asking the noob question, please bear with me.
the link for the question is How to validate child objects by implementing IDataErrorInfo on parent class.
Question is exactly the same and answer is how to achieve but what I find lacking is how to use that class for validation in Employee class.
I'm posting the same question below:
I have two model classes. Parent class has an object of another (child) class as its property. (i mean nested objects and not inherited objects)
public class AddEditItemVM
{
#region Properties/Fields
//validate here: Category cannot be empty, it has to be selected
public Category SelectedCategory
{
get => _SelectedCategory;
set
{
_SelectedCategory = value;
OnPropertyChanged(nameof(SelectedCategory));
}
}
private Category _SelectedCategory = new CCategory();
public Items Source
{
get => _Source;
set
{
_Source = value;
OnPropertyChanged(nameof(Source));
}
}
private Items _Source = new Items();
#endregion Properties/Fields
}
Category class is
public class Category
{
#region Properties/Fields
public long Id
{
get => _Id;
set
{
_Id = value;
OnPropertyChanged(nameof(Id));
}
}
long _Id;
public string Name
{
get => _Name;
set
{
_Name = value;
OnPropertyChanged(nameof(Name));
}
}
private string _Name;
#endregion Properties/Fields
}
Items class is
public class Items
{
#region Properties/Fields
public int CategoryID
{
get => _CategoryID;
set
{
_CategoryID = value;
OnPropertyChanged(nameof(CategoryID));
}
}
int _CategoryID;
//I want to validate this, item name cannot be empty and cannot greater than 20 characters
public string Name
{
get => _Name;
set
{
_Name = value;
OnPropertyChanged(nameof(Name));
}
}
string _Name = String.Empty;
//validate for percentage like percentage should be between 1 and 100
public decimal? TaxPerc
{
get => _TaxPerc;
set
{
//_TaxPerc = value;
_TaxPerc = Properties.Settings.Default.GSTPerc;
OnPropertyChanged(nameof(TaxPerc));
OnPropertyChanged(nameof(PricePlsTax));
OnPropertyChanged(nameof(TaxAmount));
}
}
decimal? _TaxPerc = null;
//price cannot be 0
//* required field!
public decimal? Price
{
get => _Price;
set
{
_Price = value;
OnPropertyChanged(nameof(Price));
OnPropertyChanged(nameof(PricePlsTax));
OnPropertyChanged(nameof(TaxAmount));
}
}
decimal? _Price = null;
#endregion Properties/Fields
}
and the person answered with validation with IDataErrorInfo (which is what I want)
public abstract class DataErrorInfo : IDataErrorInfo
{
string IDataErrorInfo.Error
{
get { return string.Empty; }
}
string IDataErrorInfo.this[string columnName]
{
get
{
var prop = this.GetType().GetProperty(columnName);
return this.GetErrorInfo(prop);
}
}
private string GetErrorInfo(PropertyInfo prop)
{
var validator = this.GetPropertyValidator(prop);
if (validator != null)
{
var results = validator.Validate(this);
if (!results.IsValid)
{
return string.Join(" ",
results.Select(r => r.Message).ToArray());
}
}
return string.Empty;
}
private Validator GetPropertyValidator(PropertyInfo prop)
{
string ruleset = string.Empty;
var source = ValidationSpecificationSource.All;
var builder = new ReflectionMemberValueAccessBuilder();
return PropertyValidationFactory.GetPropertyValidator(
this.GetType(), prop, ruleset, source, builder);
}
}
but I couldn't understand the final part i.e. implementation I mean how to use this class in the implemented class. He said to implement it by making it the parent class which is as below
public AddEditItemVM : DataErrorInfo
{
}
but I wanna know how to bind the validation with the objects.
<TextBox Text="{Binding SelectedCategory.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"></TextBox>
This will bind to your name property of your selectedcategory class and show if there is any validation errors.
I have an observable collection of Suppliers that I want to load into a gridview and then have users edit any relevant information on the supplier. My issue is I'm not sure how to implement an IsDirty field for each property on the supplier (Model) that can be changed. I have the IsDirty bits created as such
#region SupplierID
private int _SupplierID;
public int SupplierID
{
get
{
return _SupplierID;
}
set
{
if (_SupplierID != value)
{
_SupplierID = value;
OnPropertyChanged("SupplierID");
}
}
}
#endregion
#region Address
private string _Address;
public string Address
{
get
{
return _Address;
}
set
{
if (_Address != value)
{
_Address = value;
IsDirtyAddress = true;
OnPropertyChanged("Address");
}
}
}
public bool IsDirtyAddress{ get; set; }
#endregion
#region City
private string _City;
public string City
{
get
{
return _City;
}
set
{
if (_City != value)
{
_City = value;
IsDirtyCity = true;
OnPropertyChanged("City");
}
}
}
public bool IsDirtyCity { get; set; }
#endregion
#region State
private string _State;
public string State
{
get
{
return _State;
}
set
{
if (_State != value)
{
_State = value;
IsDirtyState = true;
OnPropertyChanged("State");
}
}
}
public bool IsDirtyState { get; set; }
#endregion
#region Zip
private string _Zip;
public string Zip
{
get
{
return _Zip;
}
set
{
if (_Zip != value)
{
_Zip = value;
IsDirtyZip = true;
OnPropertyChanged("Zip");
}
}
}
public bool IsDirtyZip { get; set; }
#endregion
The problem is that when I build the list of suppliers (ViewModel), I actually end up setting the IsDirty bits to true. What is the best way to set my Address, City, State, Zip when creating the supplier without setting the IsDirty bits to true. Do I need an initialization function in my Model?
for (int i = 0; i < dtSupplier.Rows.Count; i++)
{
Supplier s = new Supplier()
{
SupplierID = Convert.ToInt32(dtSupplier.Rows[i]["SupplierID"].ToString()),
Address = dtSupplier.Rows[i]["Address"].ToString(),
City = dtSupplier.Rows[i]["City"].ToString(),
State = dtSupplier.Rows[i]["State"].ToString(),
Zip = dtSupplier.Rows[i]["Zip"].ToString()
};
Suppliers.Add(s);
}
Maybe I'm going about the whole IsDirty approach the wrong way. I just want to know which values actually changed so my SQL update statement will only include the changed values when a user saves. Thanks!
You need to do a few things:
Add a flag to your ViewModel and name it Loading. When you are loading the ViewModel, set the Loading property to true. When finished loading, set it to false.
Pass your model to your ViewModel but do not expose it. Simply store it in your ViewModel.
When the property is set, check if the ViewModel is in state Loading and do not set IsDirty flags. Also, even if not in loading state, compare the values to the value in your model and see if they are the same.
Do not use hardcoded strings because it is easy to make a mistake. Use nameof (see my example below).
Do not let other people from outside set the IsDirty flag so make the setter private.
I am pretty sure there are libraries that do this already but I do not know of any so perhaps someone else can chime in.
Here is a hypothetical example:
public class Model
{
public string Name { get; set; }
}
public class ViewModel : INotifyPropertyChanged
{
private readonly Model model;
public ViewModel(Model model)
{
this.model = model;
}
public bool Loading { get; set; }
public bool IsDirtyName { get; private set; }
private string name;
public string Name
{
get
{
return this.name;
}
set
{
if (this.Loading)
{
this.name = value;
return;
}
if (this.model.Name != value)
{
IsDirtyName = true;
OnPropertyChanged(nameof(Name));
}
}
}
private void OnPropertyChanged(string propertyName)
{
// ...
}
public event PropertyChangedEventHandler PropertyChanged;
}
If you pay attention the above design, you do not even need all those IsDirty flags and IsLoading etc. You can actually just have one method in your ViewModel that you call during saving and ask it to check and return all the properties that have changed. The ViewModel will compare its own properties against the Model properties and return a dictionary. There are many ways do achieve what you want.
One option is to handle the IsDirty logic on a different class which will store the original values of the Supplier object instance. You can then use that class to GetChangedPropertyNames or check if your object HasChanges.
class Supplier
{
private string _Address;
public string Address
{
get
{
return _Address;
}
set
{
if (_Address != value)
{
_Address = value;
OnPropertyChanged("Address");
}
}
}
}
class SupplierIsDirtyTracker
{
private Dictionary<string, object> _originalPropertyValues = new Dictionary<string, object>();
private Supplier _supplier;
public void Track(Supplier supplier)
{
_supplier = supplier;
_originalPropertyValues.Add(nameof(Supplier.Address), supplier.Address);
}
public bool HasChanges()
{
return !Equals(_originalPropertyValues[nameof(Supplier.Address)], _supplier.Address);
}
public IEnumerable<string> GetChangedPropertyNames()
{
if(!Equals(_originalPropertyValues[nameof(Supplier.Address)], _supplier.Address))
{
yield return nameof(Supplier.Address);
}
}
}
You can also use Reflection on your IsDirtyTracker class to eliminate hardcoding the property names.
I have a (Devexpress) Datagrid-Control, which contains 3 columns of information. The names of the columns are generated automatically, each line describes one object of those:
private string fName;
private bool fCheck;
private DateTime fDate;
public bool checked
{
get { return this.fCheck; }
set { this.fCheck = value; }
}
public string fileName
{
get { return this.fName; }
set { this.fName = value; }
}
public DateTime createDate
{
get { return this.fDate; }
set { this.fDate = value; }
}
These Objects are saved in a List<> (dataSource):
gridFiles.DataSource = dataSource;
gridFiles.MainView.PopulateColumns();
Now, the names of the Columns are "checked","fileName" & "createDate". How can I change those?
Veeramani's answer does the job perfectly but just thought I should share an alternative solution with take less coding. You can also achieve this by adding a DisplayName attribute on each property. i.e:
My Class:
public class GridColumns
{
private string fName;
private bool fCheck;
private DateTime fDate;
[DisplayName("Checked Option")]
public bool Checked
{
get { return fCheck; }
set { this.fCheck = value; }
}
[DisplayName("File Name")]
public string fileName
{
get { return this.fName; }
set { this.fName = value; }
}
[DisplayName("Date Created")]
public DateTime createDate
{
get { return this.fDate; }
set { this.fDate = value; }
}
}
Then use it:
List<GridColumns> dataSourc = new List<GridColumns>();
dataGridView1.DataSource = dataSourc;
Using Gridview, we can rename the column name at Form_load() event...
gridView1.Columns["fileName"].Caption = "Your custom name";
I'm working on an application and spent quite some time finding a solution for the following problem. I've tried several things but I'm not sure what's the best approach to solve it.
I've got a setup of a View, ViewModel and a Model. The ViewModel contains a collection of models of which the user can select a specific model (the collection can be empty which makes the selected model null).
The View consists of a Combobox which allows the user to select a model out of a collection of models. The selected model will then be displayed in the view (with various controls such as treeviews, labels, ...).
This is the Model (I will keep it simple for the sake of explanation):
public Model {
private int id;
private String name;
public Model(_id, _name) {
id = _id;
name = _name;
}
public int ID {
get { return id; }
set { id = value; }
}
public String Name {
get { return name; }
set { name = value; }
}
}
And the ViewModel:
public ViewModel : INotifyPropertyChanged {
private ObservableCollection<Model> models = new ObservableCollection<Model>();
private Model selectedModel;
public ViewModel() { }
public Model SelectedModel {
get { return selectedModel; }
set {
selectedModel = value;
NotifyChanged("SelectedModel");
}
}
public Model ModelCellection {
get { return models; }
set {
models = value;
NotifyChanged("ModelCellection");
}
}
public void addModel(Model newModel) {
models.Add(newModel);
}
//variant A
public int ID {
get { return (selectedModel == null) ? 0 : selectedModel.ID; }
set {
if(selectedModel == null)
return;
selectedModel.ID = value;
NotifyChanged("ID");
}
}
public String Name {
get { return (selectedModel == null) ? 0 : selectedModel.Name; }
set {
if(selectedModel == null)
return;
selectedModel.Name = value;
NotifyChanged("Name");
}
}
//variant B (the attributes of the model will be copied when the selected model changes)
public void changeSelectedModel(Model newSelectedModel) {
Name = newSelectedModel.Name;
Id = newSelectedModel.Id;
}
private int id = 0;
private String name = String.Empty;
public int ID {
get { return id; }
set {
id = value;
NotifyChanged("ID");
}
}
public String Name {
get { return name; }
set {
name = value;
NotifyChanged("Name");
}
}
}
My Question is pretty simple: How do I access the relevant public properties of the Model via the ViewModel?
The solutions I've tried so far are:
Variant A: Just change the selected model and use proxy properties to access the properties of the model (problem: The view doesn't get updated when the selected model changes because the Name and Id properties of the ViewModel don't raise a PropertyChanged event)
Variant B: Copy the relevant properties of the model when the selected model is changed (problem: I have to copy the properties of the model)
After talking to some guys in the wpf chat I switched from variant B to variant A but I don't know how to solve the problem of updating the view when the selected model changes? Or would you rather suggest to use a completely different approach to solve this?
I don't know how to solve the problem of updating the view when the selected model changes?
Just raise PropertyChanged event in your SelectedModel definition
public Model SelectedModel {
get { return selectedModel; }
set {
selectedModel = value;
NotifyChanged("SelectedModel");
NotifyChanged("ID");
NotifyChanged("Name");
}
}
You have to implement INotifyPropertyChanged in your Model.
Your code look like.
Your Model.cs
public Model:INotifyPropertyChanged
{
private int id;
private String name;
public Model(_id, _name)
{
id = _id;
name = _name;
}
public int ID {
get { return id; }
set { id = value; NotifyChanged("ID");}
}
public String Name
{
get { return name; }
set { name = value; NotifyChanged("Name");}
}
}
Your ViewModel.cs
public ViewModel
{
private ObservableCollection<Model> models = new ObservableCollection<Model>();
private Model selectedModel;
public ViewModel() { }
private Model _SelectedModel ;
public Model SelectedModel
{
get { return _SelectedModel??(_SelectedModel=new SelectedModel());}
set { _SelectedModel = value;}
}
}
If property has been Changed it will aromatically Notify because in the ViewModel Model object is present.
You have to set your property like
public void changeSelectedModel(Model newSelectedModel)
{
SelectedModel.Name = newSelectedModel.Name;
SelectedModel.Id = newSelectedModel.Id;
}
and it will Notify.
I'm very new to C#/LINQ/WP7 development and am struggling to format data being returned from my LINQ query.
I have the following LINQ c# structure:
var boughtItemsInDB = from DBControl.MoneySpent bought in BoughtItemDB.BoughtItems
select bought;
BoughtItems = new ObservableCollection<DBControl.MoneySpent>(boughtItemsInDB);
The definition for MoneySpent is below;
[Table(Name = "MoneySpent")]
public class MoneySpent : INotifyPropertyChanged, INotifyPropertyChanging
{
// Define ID: private field, public property and database column.
private int _itemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ItemId
{
get
{
return _itemId;
}
set
{
if (_itemId != value)
{
NotifyPropertyChanging("ItemId");
_itemId = value;
NotifyPropertyChanged("ItemId");
}
}
}
// Define item budget: private field, public property and database column.
private int _itemBudget;
[Column]
public int ItemBudget
{
get
{
return _itemBudget;
}
set
{
if (_itemBudget != value)
{
NotifyPropertyChanging("ItemBudget");
_itemBudget = value;
NotifyPropertyChanged("ItemBudget");
}
}
}
// Define item category: private field, public property and database column.
private string _itemCategory;
[Column]
public string ItemCategory
{
get
{
return _itemCategory;
}
set
{
if (_itemCategory != value)
{
NotifyPropertyChanging("ItemCategory");
_itemCategory = value;
NotifyPropertyChanged("ItemCategory");
}
}
}
// Define item description: private field, public property and database column.
private string _itemDescription;
[Column]
public string ItemDescription
{
get
{
return _itemDescription;
}
set
{
if (_itemDescription != value)
{
NotifyPropertyChanging("ItemDescription");
_itemDescription = value;
NotifyPropertyChanged("ItemDescription");
}
}
}
// Define item amount: private field, public property and database column.
private decimal _itemAmount;
[Column]
public decimal ItemAmount
{
get
{
return _itemAmount;
}
set
{
if (_itemAmount != value)
{
NotifyPropertyChanging("ItemAmount");
_itemAmount = value;
NotifyPropertyChanged("ItemAmount");
}
}
}
// Define item date: private field, public property and database column.
private DateTime _itemDateTime;
[Column]
public DateTime ItemDateTime
{
get
{
return _itemDateTime;
}
set
{
if (_itemDateTime != value)
{
NotifyPropertyChanging("ItemDateTime");
_itemDateTime = value;
NotifyPropertyChanged("ItemDateTime");
}
}
}
I need to format the data returned from the database, the following is stored in my DB:
ItemDateTime - DateTime, ItemDescription - String, ItemAmount - Decimal
I need to be able to to format the Date based on the current locale of the user, and format the decimal to 2 dp.
I am also not sure if I need to use IQueryable when I get the data results .
Any help would be much appreciated.
Thanks,
Mark
Since you don't provide enough detail - just a general idea
var boughtItemsInDB = from bought in BoughtItemDB.BoughtItems
select new { ItemDateTime = bought.ItemDateTime.ToString(), ItemDescription = bought.ItemDescription, ItemAmount = bought.ItemAmount.ToString("0,0.00") };
BUT formatting is better done in the control you use to display the data, not in the Linq query...
EDIT - after the addition frm OP:
From what I see the MoneySpent class is already prepared for "data binding"...
So formatting should be done in the displaying control... for some information see:
What is the WPF XAML Data Binding equivalent of String.Format?
http://www.codeproject.com/KB/WPF/binding_in_linq-sql.aspx
http://odetocode.com/code/740.aspx
http://www.codeguru.com/csharp/.net/wp7/article.php/c18933