Caliburn.micro datagrid deleted button - wpf

I am learning Caliburn.Micro. I am storing data from database into the DataGrid. I am able to access the data but not able to delete the data from DataGrid in CaliBurn.Micro. In my project I wants to have delete button in every row so that whenever i click the button of specific row then that row data will be deleted. I have tried but it is not working.
Here is my code
ShellView.xaml
<Button x:Name="ButtonUpdate" Width="100" Height="30" Content="Update"/>
<DataGrid x:Name="Empdata2" AutoGenerateColumns="False" ItemsSource="{Binding Path= Empdata}" SelectedItem="{Binding selecteditem}" Height="162" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Header=" First Name" Binding="{Binding Path= fname}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding Path=lname}"/>
<DataGridTemplateColumn Header="delete">
<DataGridTemplateColumn.CellTemplate >
<DataTemplate>
<Button Content="Delete" x:Name="DeleteButton"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
ShellViewModel.cs
public class ShellViewModel : Caliburn.Micro.PropertyChangedBase, IShell
{
private string _firstname, _lastname;
private ObservableCollection<Person> _empdata = new ObservableCollection<Person>();
public ObservableCollection<Person> Empdata
{
get { return _empdata; }
set
{
_empdata = value;
NotifyOfPropertyChange(() => Empdata);
}
}
Person model = new Person();
public string FirstName
{
get { return _firstname; }
set { _firstname = value; }
}
public string LastName
{
get { return _lastname; }
set { _lastname = value; }
}
Auth obj = new Auth();
public void ButtonUpdate()
{
DataSet d = new DataSet();
d = obj.updateuser();
for (int i = 0; i < d.Tables[0].Rows.Count; i++)
Empdata.Add(new Person
{
fname = d.Tables[0].Rows[i][0].ToString(),
lname = d.Tables[0].Rows[i][1].ToString(),
});
}
private Person _selecteditem;
public Person selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
NotifyOfPropertyChange(() => selecteditem);
}
}
string sel;
public void DeleteButton()
{
Auth obj = new Auth();
sel = selecteditem.fname.ToString();
bool find = obj.deluser(sel);
if (find == true)
{
MessageBox.Show("Deleted");
}
}
}
Person.cs
public class Person:PropertyChangedBase
{
public string FirstName { get; set; }
public string LastName { get; set; }
private string Firstname;
public string fname
{
get { return Firstname; }
set
{
Firstname = value;
NotifyOfPropertyChange(() => fname);
}
}
private string Lastname;
public string lname
{
get { return Lastname; }
set
{
Lastname = value;
NotifyOfPropertyChange(() => lname);
}
}
}
Auth.cs
public class Auth
{
SqlConnection conn = new SqlConnection(#"Data Source = a; Initial Catalog = ab; Persist Security Info=True;User ID = s; Password=123");
public DataSet updateuser()
{
try
{
conn.Open();
SqlCommand comm = new SqlCommand("Select * from [add]", conn);
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(comm);
da.Fill(ds);
conn.Close();
return ds;
}
catch (Exception ex)
{
throw ex;
}
}
public bool deluser(string name)
{
try
{
conn.Open();
SqlCommand comm = new SqlCommand("Delete from [add] where firstname=" + name + "", conn);
comm.ExecuteNonQuery();
conn.Close();
return true;
}
catch(Exception ex)
{
throw ex;
}
}
}

Set the cal:Bind.Model attached property to your view model:
<DataTemplate xmlns:cal="http://www.caliburnproject.org">
<Button Content="Press Me" VerticalAlignment="Top"
cal:Bind.Model="{Binding DataContext, RelativeSource={RelativeSource AncestorType=DataGrid}}"
x:Name="DeleteButton" />
</DataTemplate>
Then the DeleteButton method of the ShellViewModel should be called when the button is clicked.

Related

WPF MVVM DataGrid populate with query at run time

Being new to WPF and MVVM I've been struggling for the last few days trying to solve this issue. I've searched all over stackoverflow and google/Youtube for help.
I have a DataGrid (biound from OrderListView) that is populated from a BindableCollection (Caliburn Micro) of a model. However I need to bring in a property ('Program') of linked data from another BindableCollection ProductList, (both collections share a common property 'Code'.
Basically I want the DataGrid to show all the OrderModel based columns and fill a column called Programs with the related data from the Products collection just at run time.
OrderModel.cs
public class OrderModel : BaseModel
{
private DateTime _orderDate;
public DateTime OrderDate
{
get { return _orderDate; }
set { _orderDate = value; OnPropertyChanged(); }
}
private string _code;
public string Code
{
get { return _code; }
set { _code = value; OnPropertyChanged(); }
}
private int _qty;
public int Qty
{
get { return _qty; }
set { _qty = value; OnPropertyChanged(); }
}
ProductModel.cs
public class ProductModel : BaseModel
{
private string _code;
public string Code
{
get { return _code; }
set { _code = value; OnPropertyChanged(); }
}
private int _program;
public int Program
{
get { return _program; }
set { _program = value; OnPropertyChanged(); }
}
DataGrid in OrderView.xaml
<DataGrid ItemsSource="{Binding OrderListView}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Code}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Qty}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Program}"/> <- This from ProductList ??
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
OrderViewModel.cs
public class OrderViewModel : Screen
{
private readonly IDataConnection _connect;
private ICollectionView _orderView;
public ICollectionView OrderListView
{
get => _orderView;
set
{
_orderView = value;
NotifyOfPropertyChange(() => OrderListView);
}
}
private BindableCollection<OrderModel> _orderList;
public BindableCollection<OrderModel> OrderList
{
get => _orderList;
set
{
_orderList = value;
NotifyOfPropertyChange(() => OrderList);
}
}
private BindableCollection<ProductModel> _productList;
public BindableCollection<ProductModel> ProductList
{
get { return _productList; }
set { _productList = value; }
}
private string _code;
public string Code
{
get { return _code; }
set { _code = value; NotifyOfPropertyChange(() => Code); }
}
private int _qty;
public int Qty
{
get { return _qty; }
set { _qty = value; NotifyOfPropertyChange(() => Qty); }
}
private int _program;
public int Program
{
get { return _program; }
set
{
_program = value;
NotifyOfPropertyChange(() => Program);
}
}
public OrderViewModel(IDataConnection connect)
{
DisplayName = "Orders";
var allOrders = await _connect.Orders_GetByDateRange(StartDate, EndDate);
OrderList = new BindableCollection<OrderModel>(allOrders);
OrderListView = CollectionViewSource.GetDefaultView(OrderList);
var allProducts = await _connect.Products_GetAll();
ProductList = new BindableCollection<ProductModel>(allProducts);
}
}
Basically where 'Code' Matches in the models i want to pull the associated Program into the column.
The ItemsSource that a DataGrid binds to needs to contain all the properties for the column bindings.
Which means either a Program property needs to be added to your current OrderModel or create a new model that contains both properties.
public class OrderModel : BaseModel
{
private DateTime _orderDate;
public DateTime OrderDate
{
get { return _orderDate; }
set { _orderDate = value; OnPropertyChanged(); }
}
private string _code;
public string Code
{
get { return _code; }
set { _code = value; OnPropertyChanged(); }
}
private int _qty;
public int Qty
{
get { return _qty; }
set { _qty = value; OnPropertyChanged(); }
}
private int _program;
public int Program
{
get { return _program; }
set { _program = value; OnPropertyChanged(); }
}
}
Then there will be logic needed to link the new Program value with the value from the other collection.
The cleanest place for this would most likely be to modify your query (assuming you are using a database connection)
Most likely this would be to include a JOIN when doing the selection for the Orders.
However, doing this on the client side, meaning after the data has been recieved from the IDataConnection would look like this:
using System.Linq;
...
public OrderViewModel(IDataConnection connect)
{
DisplayName = "Orders";
var allOrders = await _connect.Orders_GetByDateRange(StartDate, EndDate);
var allProducts = await _connect.Products_GetAll();
ProductList = new BindableCollection<ProductModel>(allProducts);
foreach(var order in allOrders)
{
//assumes "Code" is unique within `ProductList`
order.Program = ProductList.Single(p => p.Code == order.Code);
}
OrderList = new BindableCollection<OrderModel>(allOrders);
OrderListView = CollectionViewSource.GetDefaultView(OrderList);
}

Add and Biding comboboxEdit DevExpress

Im trying to bind one combobox from my class that i linked in the context
i have this in the control
<dxe:ComboBoxEdit Width="100" Margin="5" Name="cboProduct" DisplayMember="Name"
SelectedItem="{Binding Path=DataContext.SelectedProduct, Mode=OneWay, RelativeSource={RelativeSource AncestorType=Window}}"
>
</dxe:ComboBoxEdit>
I filled the Combobox befor from code behind like this
var lsproducts = new List<Product>();
var Products =_licenseService.GetProductList();
Products.ForEach((x) => {
lsproducts.Add(new Product(x.Name, x.ProductId));
});
And im setting the SelectedProduct like this
[DataMember]
public License SelectedLicense {
get { return _SelectedLicense;}
set {
_SelectedLicense = value;
this.NotifyPropertyChanged("SelectedLicense");
}
}
public Product SelectedProduct
{
get
{
return new Product(_SelectedLicense.Product.Name,_SelectedLicense.Product.ProductId);
}
}
this.cboProduct.ItemsSource = lsproducts.ToArray();
in both cases im using the object Product
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using pd.Common.Domain;
namespace LicenceManagerWPF.Views
{
public class Product
{
public string Name { get; set; }
public ProductEnum ProductID { get; set; }
public Product(string ProductName,ProductEnum ID)
{
Name = ProductName;
ProductID = ID;
}
}
i dont know why its not selecting the product when i open the window.
i have another one
[![Shows like this][2]][2]
I dont know why its display the x mark, but when i chouse another licence it updated the combo selection
<dxe:ComboBoxEdit x:Name="cboActivationMode" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Width="100" Style="{StaticResource TabMargin}"
SelectedItem="{Binding Path=DataContext.SelectedLicense.ActivationMode, RelativeSource={RelativeSource AncestorType=Window}}"
/>
The second one its only a couple of enums values that fill like this.
cboActivationMode.Items.Add(
new DevExpress.Xpf.Editors.ComboBoxEditItem()
{ Content = Enum.GetName(typeof(ActivationMode), ActivationMode.Online), Tag = ActivationMode.Online });
How can i bind the values to a combobox?
Regards
cboActivationMode.Items.Add(
new DevExpress.Xpf.Editors.ComboBoxEditItem()
{Content = Enum.GetName(typeof(ActivationMode), ActivationMode.Offline),Tag = ActivationMode.Offline});
I tryed to do this
public partial class LicenseDetail : UserControl
{
private readonly LicenseService _licenseService;
public LicenseDetail()
{
InitializeComponent();
_licenseService = new LicenseService();
FillCombos();
}
private void FillCombos()
{
FillProducts();
FillActivationMode();
//var str = Enum.GetName(typeof(ProductEnum), ProductEnum.CDSAddIn);
//this.cboProduct.ItemsSource = new string[] { str };
}
private void FillProducts()
{
var Products = _licenseService.GetProductList();
cboProduct.ItemsSource = Products;
}
The product list is a list of Iproduct (interface), i dont get i why they made it like this but each product is diferent they implement the same baseclass and the interface
[DataContract]
public class ProductList : List<IProduct>
{
public bool Contains(ProductEnum productId)
{
return this.Any(x => x.ProductId == productId);
}
public IProduct GetProduct(ProductEnum productId)
{
return this.FirstOrDefault(x => x.ProductId == productId);
}
public void Remove(ProductEnum productId)
{
Remove(GetProduct(productId));
}
}
I changed the combo to bind like this
SelectedItem="{Binding Path=DataContext.MyProduct, RelativeSource={RelativeSource AncestorType=Window}}"
I create the property in the class like this
public IProduct MyProduct
{
get { return _MyProduct; }
set
{
_MyProduct = value;
this.NotifyPropertyChanged("MyProduct");
}
}
And assaing like this
_CustomerLicense.MyProduct = SelectedLicense.Product;
this is how the list of products is filled
public IProduct GetProduct(ProductEnum productId)
{
IProduct product = null;
var connection = GetConnection();
try
{
var sql = string.Format(Resources.GetProduct, (int)productId);
var cmd = new SqlCommand(sql, connection) { CommandType = CommandType.Text, Transaction = _transaction };
using (var rdr = new NullableDataReader(cmd.ExecuteReader()))
while (rdr.Read())
{
var productName = rdr.GetString(0);
var featureId = rdr.GetInt32(1);
var featureDesc = rdr.GetString(2);
if (product == null)
{
switch (productId)
{
case ProductEnum.PDCalc:
product = new PDCalcProduct(productId, productName);
break;
case ProductEnum.PDMaint:
product = new PDMaintProduct(productId, productName);
break;
case ProductEnum.PBDynamics:
product = new PBDynamicsProduct(productId, productName);
break;
case ProductEnum.CDSAddIn:
product = new CDSAddInProduct(productId, productName);
break;
}
}
if (product != null)
product.Features.Add(new Feature((FeatureEnum)featureId, featureDesc));
}
}
finally
{
CloseConnection(connection);
}
return product;
}
without any luck.
Regards
The SelectedProduct property should have a public setter for you to be able to set it to the currently selected value in the ComboBox:
private Product _selectedProduct;
public Product SelectedProduct
{
get { return _selectedProduct; }
set
{
_selectedProduct = value;
this.NotifyPropertyChanged("SelectedProduct");
}
}
And for the intial value to be selected, you either need to set it to a Product object that is actually in the ItemsSource (lsproducts):
viewModel.SelectedProduct = lsproducts.FirstOrDefault(x => x.Name == _SelectedLicense.Product.Name && x.ProductID == _SelectedLicense.Product.ProductId);
Or you will have to override the Equals method of your Product class:
public class Product
{
public string Name { get; set; }
public ProductEnum ProductID { get; set; }
public Product(string ProductName, ProductEnum ID)
{
Name = ProductName;
ProductID = ID;
}
public override bool Equals(object obj)
{
Product other = obj as Product;
return other != null && Name == other.Name && ProductID == other.ProductID;
}
}
I fixed like this:
I created the method :
private void GetProducts()
{
var Products = new LicenseService().GetProductList();
Products.ForEach((x) =>
{
lsproducts.Add(new Product(x.Name, x.ProductId));
});
//this.cboProduct.ItemsSource = lsproducts.ToArray();
}
Then i attached to the load of the main windows, where all the controls are
public frmCustomerLicense(CustomerLicenses cl)
{
InitializeComponent();
GetProducts();
_CustomerLicense = cl;
grdLicenses.grdLicences.SelectedItemChanged += GridRowSelected;
}
Then when one of the licenses is selected i set all the bindings
var Record = (DataRowView)grdLicenses.grdLicences.SelectedItem;
var SelectedLicense = (License)Record["License"];
var list = new LicenseService().GetActivityLog(SelectedLicense.SerialNumber)
.OrderByDescending(x => x.ActivityDate)
.ToList();
_CustomerLicense.ActivityLog = list;
_CustomerLicense.Features = new LicenseService().GetFeatures(SelectedLicense.Product.ProductId);
_CustomerLicense.Products = lsproducts;
_CustomerLicense.HasExpDate = SelectedLicense.HasExpirationDate;
//_CustomerLicense.SetLog(list);
_CustomerLicense.SelectedLicense = SelectedLicense;
//_CustomerLicense.SelectedMaintenance = SelectedLicense.Product.ProductId == ProductEnum.PDMaint ? true : false;
_CustomerLicense.SelectedProduct = lsproducts.FirstOrDefault((x) => x.ProductID == SelectedLicense.Product.ProductId);
And in my ViewClass i added this
[DataMember]
public Product SelectedProduct
{
get { return _SelectedProduct; }
set
{
_SelectedProduct = value;
this.NotifyPropertyChanged("SelectedProduct");
}
}
[DataMember]
public List<Product> Products
{
get { return _Products; }
set { _Products = value;
this.NotifyPropertyChanged("Products");
}
}
So, i set the combobox
<dxe:ComboBoxEdit Width="180" Margin="5" Name="cboProduct" DisplayMember="Name"
ItemsSource="{Binding Path=DataContext.Products, RelativeSource={RelativeSource AncestorType=Window}}"
SelectedItem="{Binding Path=DataContext.SelectedProduct, RelativeSource={RelativeSource AncestorType=Window}}"
>
</dxe:ComboBoxEdit>
Doing this works, thanks for your help mm8

Correct way to data-bind collections to ComboBox in WPF using MVVM?

I'm using MVVM pattern, developing my WPF application. I also use Entity Framework as ORM. Here're my models (EF):
public class User : BaseEntity
{
public string Name { get; set; }
public int OfficeId { get; set; }
public Office Office { get; set; }
}
public class Office : BaseEntity
{
public string Name { get; set; }
public int DepartmentId { get; set; }
public Department Department { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Department : BaseEntity
{
public string Name { get; set; }
public virtual ICollection<Office> Offices { get; set; }
}
Let's assume, that I've got an instance of User class from my context:
var userInstance = context.Get<User>().Single(user => user.ID == 1);
Now I'd like to pass this instance to my View to make some changes for concrete user (called, for example, UserEditView), so I have to create a UserModel class to deal with User data according to MVVM. So, here's what I think I have to write in my code:
public class UserModel : ObservableObject
{
private User user;
public string Office Office
{
get
{
return this.user.Office.Name;
}
set
{
//what shoud I write Here??
if(value != user.Office)
{
user.Office=value;
OnPropertyChanged("Office");
}
}
}
}
I'm really frustrated! How should I deal with that? There're thousands of examples, but they are so simple. I'm wondering what should I do to have a ComboBox in my EditView with a list of all Offices, existing in my DB. And list of Offices should depend on another one Combobox, which contains a list of Departments.
But where should I get this lists from?
Should I pass a collection from my UserModel? Or what?
Can anybody give me a simple example about how to do this correctly?
PS: Of course, I know couple ways to implement such behaviour, but in that case my code seems to be ugly and not maintainable. Please, help. Thanks a lot!
this is depends on your DB architecture. Here is some common suggestion (but there can be a lot of others).
Don't panic - you have a correct question.
Create the view model set it to be a main view model of your window.
In your view model create two collections Users (containing UserModels) and Departments (containing DepartmentMode), since you want to change offices each time you re-select department, you don't need the Offices collection in main view model.
Pull each collection data from your data base.
Implement each model with INPC.
Take in account the WPF MVVM best practices.
Apply a correct bindings.
And be happy - you are a programmer.
Updates - 1
XAML code
<Grid x:Name="LayoutRoot">
<Grid.DataContext>
<someBindingExampleSoHelpAttempt:MainViewModel/>
</Grid.DataContext>
<ListView ItemsSource="{Binding Users}">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="someBindingExampleSoHelpAttempt:UserModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding Name, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
<TextBox Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="{Binding LastName, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"/>
<ComboBox Grid.Column="2"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
TextSearch.TextPath="DepartmentName"
ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}, Path=DataContext.Departments}"
SelectedValue="{Binding Department}"
DisplayMemberPath="DepartmentName"
IsEditable="True"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<ComboBox Grid.Column="3"
IsTextSearchEnabled="True"
IsTextSearchCaseSensitive="False"
StaysOpenOnEdit="True"
IsEditable="True"
TextSearch.TextPath="OfficeName"
ItemsSource="{Binding OfficesCollection}"
SelectedValue="{Binding Office}"
DisplayMemberPath="OfficeName"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView></Grid>
VM and models
public class MainViewModel:BaseObservableObject
{
private DepartmentModel _selectedDepartment;
private OfficeModel _selectedOffice;
public MainViewModel()
{
Dal = new DataLayer();
Users = new ObservableCollection<UserModel>();
Departments = new ObservableCollection<DepartmentModel>(Dal.GetAllDepartments());
InitUsersCollection();
}
private void InitUsersCollection()
{
if(Departments == null) return;
Departments.ToList().ForEach(model =>
{
model.Offices.ToList().ForEach(officeModel =>
{
if (officeModel.Users == null) return;
officeModel.Users.ToList().ForEach(userModel => Users.Add(userModel));
});
});
}
public ObservableCollection<UserModel> Users { get; set; }
public ObservableCollection<DepartmentModel> Departments { get; set; }
private DataLayer Dal { get; set; }
}
public class DataLayer
{
public List<DepartmentModel> GetAllDepartments()
{
//pull and map your using your DB service
//For example:
return new List<DepartmentModel>
{
new DepartmentModel
{
DepartmentId = 1,
DepartmentName = "A",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel
{
DepartmentId = 1,
OfficeName = "AA",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "Avicenna", LastName = "Abu Ali Abdulloh Ibn-Sino"},
new UserModel {Name = "Omar", LastName = "Khayyam"},
new UserModel {Name = "RAMBAM", LastName = "Moshe ben Maimon"}
})
},
new OfficeModel
{
DepartmentId = 1,
OfficeName = "AB",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "Leo", LastName = "Tolstoi"},
new UserModel {Name = "Anton", LastName = "Chekhov"},
})},
}
},
new DepartmentModel
{
DepartmentId = 2,
DepartmentName = "B",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel
{
DepartmentId = 2, OfficeName = "BA",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "B", LastName = "O"},
new UserModel {Name = "B", LastName = "N"},
}),
},
new OfficeModel
{
DepartmentId = 2, OfficeName = "BB",
Users = new ObservableCollection<UserModel>(new List<UserModel>
{
new UserModel {Name = "John", LastName = "Walker"},
new UserModel {Name = "Gregory", LastName = "Rasputin"},
}),
},
}
},
new DepartmentModel
{
DepartmentId = 3,
DepartmentName = "C",
Offices = new ObservableCollection<OfficeModel>
{
new OfficeModel {DepartmentId = 3, OfficeName = "CA"},
new OfficeModel {DepartmentId = 3, OfficeName = "CB"},
new OfficeModel {DepartmentId = 3, OfficeName = "CC"}
}
}
};
}
}
public class OfficeModel:BaseObservableObject
{
private int _departmentModel;
private string _officeName;
private DepartmentModel _department;
private ObservableCollection<UserModel> _users;
public int DepartmentId
{
get { return _departmentModel; }
set
{
_departmentModel = value;
OnPropertyChanged();
}
}
public DepartmentModel Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged();
}
}
public string OfficeName
{
get { return _officeName; }
set
{
_officeName = value;
OnPropertyChanged();
}
}
public ObservableCollection<UserModel> Users
{
get { return _users; }
set
{
_users = value;
OnPropertyChanged(()=>Users);
}
}
}
public class DepartmentModel:BaseObservableObject
{
private string _departmentName;
public string DepartmentName
{
get { return _departmentName; }
set
{
_departmentName = value;
OnPropertyChanged();
}
}
public int DepartmentId { get; set; }
public ObservableCollection<OfficeModel> Offices { get; set; }
}
public class UserModel:BaseObservableObject
{
private string _name;
private string _lastName;
private DepartmentModel _department;
private OfficeModel _office;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
OnPropertyChanged();
}
}
public DepartmentModel Department
{
get { return _department; }
set
{
_department = value;
OnPropertyChanged();
OnPropertyChanged(()=>OfficesCollection);
}
}
public ObservableCollection<OfficeModel> OfficesCollection
{
get { return Department.Offices; }
}
public OfficeModel Office
{
get { return _office; }
set
{
_office = value;
OnPropertyChanged();
}
}
}
/// <summary>
/// implements the INotifyPropertyChanged (.net 4.5)
/// </summary>
public class BaseObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged<T>(Expression<Func<T>> raiser)
{
var propName = ((MemberExpression)raiser.Body).Member.Name;
OnPropertyChanged(propName);
}
protected bool Set<T>(ref T field, T value, [CallerMemberName] string name = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(name);
return true;
}
return false;
}
}
But please take in account that this is only one of hundreds ways to do that.
The SO here if you will need the code example.
Regards.

Why is not ICollectionView refreshed?

I cant figureout why my ICollectionView is not refreshed. Can anyone explain what I'm doing wrong?
I've made a viewmodel like this:
class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Entity> m_entities = new ObservableCollection<Entity>();
public ICollectionView EntitiesView { get; private set; }
public ICollectionView HighCountView { get; private set; }
public ViewModel()
{
m_entities.Add(new Entity() { Id = 1, Name = "Erik", Description = "The first" });
m_entities.Add(new Entity() { Id = 2, Name = "Olle", Description = "The second" });
m_entities.Add(new Entity() { Id = 3, Name = "Kim", Description = "The last" });
EntitiesView = CollectionViewSource.GetDefaultView(m_entities);
EntitiesView.CurrentChanged += new EventHandler(EntitiesView_CurrentChanged);
HighCountView = new CollectionView(m_entities);
using (HighCountView.DeferRefresh())
{
HighCountView.Filter = e => ((Entity)e).Count > 3;
}
}
private void EntitiesView_CurrentChanged(object sender, EventArgs e)
{
Entity current = EntitiesView.CurrentItem as Entity;
if(current!=null)
{
current.Count++;
HighCountView.Refresh(); // Do I need this line?
OnPropertyChanged("HighCountView"); // or this?
}
}
...and in my window I use it as the datacontext, like this:
public partial class MainWindow : Window
{
private ViewModel vm = new ViewModel();
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.DataContext = vm;
}
}
...and I'm doing my bindings in the XAML-code like this:
<ListBox Grid.Column="0" x:Name="listView1" DisplayMemberPath="Name" ItemsSource="{Binding EntitiesView}" IsSynchronizedWithCurrentItem="True" />
<ListView Grid.Column="1" x:Name="listView2" DisplayMemberPath="Name" ItemsSource="{Binding HighCountView}" IsSynchronizedWithCurrentItem="True" />
The problem is that all three Entities is always shown in listView2 despite that I set the Filter-property. Why?
EDIT
To made the sample complete, here is the Entity-class.
class Entity : INotifyPropertyChanged
{
private int m_id;
public int Id
{
bla bla.....
}
private string m_name;
public string Name
{
bla bla.....
}
private string m_description;
public string Description
{
bla bla.....
}
private int m_count;
public int Count
{
get { return m_count; }
set
{
if (value != m_count)
{
m_count = value;
OnPropertyChanged("Count");
}
}
}
public void Update()
{
Description = "Updated: " + (++Count).ToString() + " times.";
}
At last I found what was wrong.
If I change the line:
HighCountView = new CollectionView(m_entities);
to this
HighCountView = new ListCollectionView(m_entities);
then it works a expected.
I can also remove this line
OnPropertyChanged("HighCountView"); // or this?
I hope this can help somebody!

Problem with binding Stacked colums series chart to Series

i have big problem with binding Stacked Column Series to my chart.
I have
public ObservableCollection Series property in my ViewModel and try by many ways but it still not working.
This is code from ViewModel to prepare Series:
private void drawChart()
{
this.Series.Clear();
var dataValues = new List<List<SimpleDataValue>>();
int wartoscNiezalezna = 1;
for (int i = 0; i < 2; i++)
{
dataValues.Add(new List<SimpleDataValue>());
}
foreach (var item in myCollection)
{
var param = someparam;
dataValues[0].Add(new SimpleDataValue { IndependentValue = "Czujnik " + wartoscNiezalezna, DependentValue = 100 });
//czerwone
dataValues[1].Add(new SimpleDataValue { IndependentValue = "" + wartoscNiezalezna, DependentValue = 200 });
wartoscNiezalezna++;
}
var stackedSeries = Activator.CreateInstance(typeof(StackedColumnSeries)) as DefinitionSeries;
int itemnr=0;
foreach (var item in dataValues)
{
var definicja = new SeriesDefinition();
if(itemnr==0)
definicja.Title = "Stan 1";
else
definicja.Title = "Stan 2";
definicja.DependentValuePath = "DependentValue";
definicja.IndependentValuePath = "IndependentValue";
definicja.ToolTip = "asdas";
definicja.ItemsSource = item;
stackedSeries.SeriesDefinitions.Add(definicja);
itemnr++;
}
Series.Add(stackedSeries);
}
I cant bind it to:
<charting:Chart x:Name="MyChart" Padding="10,10,10,10">
<charting:Chart.Series>
<charting:StackedColumnSeries>
<charting:SeriesDefinition ItemsSource="{Binding Series}" DependentValuePath="DependentValue" IndependentValuePath="IndependentValue">
</charting:SeriesDefinition>
</charting:StackedColumnSeries>
</charting:Chart.Series>
</charting:Chart>
I was trying with SeriesDefinitions Collection and others.
I will be very grateful to some help.
I hope I've answered your question there
Anyway I post the second part of my answer here:
MainWindow.xaml:
<charting:Chart x:Name="MyChart" Padding="10,10,10,10">
<charting:Chart.Series>
<charting:StackedColumnSeries>
<charting:SeriesDefinition Title="Stan 1" ItemsSource="{Binding FirstCollection}" DependentValuePath="DependentValue" IndependentValuePath="IndependentValue" />
<charting:SeriesDefinition Title="Stan 2" ItemsSource="{Binding SecondCollection}" DependentValuePath="DependentValue" IndependentValuePath="IndependentValue" />
</charting:StackedColumnSeries>
</charting:Chart.Series>
</charting:Chart>
MainWindow.xaml.cs
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
this.MyChart.DataContext = new ChartModel
{
FirstCollection = Enumerable.Range(1, 10).Select(i => new SimpleDataValue { IndependentValue = "Czujnik " + i, DependentValue = 100 }).ToList(),
SecondCollection = Enumerable.Range(1, 10).Select(i => new SimpleDataValue { IndependentValue = "" + i, DependentValue = 200 }).ToList()
};
}
}
public class SimpleDataValue
{
public string IndependentValue { get; set; }
public int DependentValue { get; set; }
}
public class ChartModel
{
public List<SimpleDataValue> FirstCollection { get; set; }
public List<SimpleDataValue> SecondCollection { get; set; }
}
I am not sure with the syntax but the logic should be like below:
ViewModel
public class GraphItem {
public string IndependentValue { get; set; }
public int DependentValue1 { get; set; }
public int DependentValue2 { get; set; }
}
public class ChartViewModel
{
private List<GraphItem> itemCollection;
public List<GraphItem> ItemCollection
{
get { return itemCollection;}
set {
itemCollection=value;
OnPropertyChanged("ItemCollection");
}
}
public ChartViewModel()
{
//Bind ItemCollection
}
}
Xaml:
<charting:Chart x:Name="MyChart" Padding="10,10,10,10" DataContext={Binding ItemCollection}">
<charting:Chart.Series>
<charting:StackedColumnSeries>
<charting:SeriesDefinition Title="Stan 1" ItemsSource="{Binding}" DependentValuePath="DependentValue1" IndependentValuePath="IndependentValue" />
<charting:SeriesDefinition Title="Stan 2" ItemsSource="{Binding}" DependentValuePath="DependentValue2" IndependentValuePath="IndependentValue" />
</charting:StackedColumnSeries>
</charting:Chart.Series>
</charting:Chart>
May this help.

Resources