DataGrid CheckBox can't be checked - wpf

I got a problem with datagrid and DataGridCheckBoxClumn. First of all im creating struct for datagrid items:
public struct taxRateFromDatabase
{
public int rate { get; set; }
public string mark { get; set; }
public CheckBox c { get; set; }
}
And after that in my class adding columns, bindings etc:
StackPanel tSp = new StackPanel();
DataGrid taxRateDataGrid = new DataGrid();
DataGridTextColumn col0 = new DataGridTextColumn();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridCheckBoxColumn col2 = new DataGridCheckBoxColumn();
Binding b = new Binding("checkBox");
b.Mode = BindingMode.TwoWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
taxRateDataGrid.Columns.Add(col0);
taxRateDataGrid.Columns.Add(col1);
taxRateDataGrid.Columns.Add(col2);
col0.Binding = new Binding("rate");
col1.Binding = new Binding("mark");
col2.Binding = b;
CheckBox c = new CheckBox();
c.Content = "a";
col0.Header = "Stawka";
col1.Header = "Oznaczenie";
col2.Header = "Status";
taxRateDataGrid.Items.Add(new taxRateFromDatabase { rate = 0, mark = "E", c = c });
taxRateDataGrid.Items.Add(new taxRateFromDatabase { rate = 1, mark = "G", c = c });
Problem is that I cant really check/uncheck that checkbox i have just added.
I have tried also without checkbox in struct definition (just empty datagridcheckboxcolumn), but that also doesnt work. Im creating it in class which will return datagrid so i cant really acces xaml.
Any sugestions will be appreciated ;)

I suggest you to use class instead struct (take a look here) and implement INotifyPropertyChanged interface in order to get the binding working.
Something like
public class TaxRateFromDatabase : INotifyPropertyChanged
{
private int _rate;
public int Rate
{
get { return _rate; }
set { _rate = value; OnPropertyChanged("Rate"); }
}
private string _mark;
public string Mark
{
get { return _mark; }
set { _mark = value; OnPropertyChanged("Mark"); }
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
and for example
DataGrid taxRateDataGrid = new DataGrid();
DataGridTextColumn col0 = new DataGridTextColumn();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridCheckBoxColumn col2 = new DataGridCheckBoxColumn();
taxRateDataGrid.Columns.Add(col0);
taxRateDataGrid.Columns.Add(col1);
taxRateDataGrid.Columns.Add(col2);
col0.Binding = new Binding("Rate");
col1.Binding = new Binding("Mark");
col2.Binding = new Binding("IsChecked");
col0.Header = "Stawka";
col1.Header = "Oznaczenie";
col2.Header = "Status";
List<TaxRateFromDatabase> list = new List<TaxRateFromDatabase>();
list.Add(new TaxRateFromDatabase { Rate = 1, Mark = "E", IsChecked = true });
list.Add(new TaxRateFromDatabase { Rate = 23, Mark = "F", IsChecked = false });
taxRateDataGrid.ItemsSource = list;

Related

Handling events across different classes using C#

I have a property defined in Class A. When the property is changed then i need to raise an event. Another class B should respond to this event and do something. I have done something like this:
Code:
Class A{
string variable = "test";
public delegate void EventHandler(object sender, EventArgs args);
public static event EventHandler ThrowAddEvent = delegate { };
public static event EventHandler ThrowRemoveEvent = delegate { };
public String Name { get; set; }
public int Select { get; set; }
public Window Formref1 { get; set; }
public bool IsSelected
{
get { return IsSlctd; }
set
{
IsSlctd = value;
if (value)
{
ThrowAddEvent(this, new EventArgs());
}
else
{
ThrowRemoveEvent(this, new EventArgs());
}
}
}
}
Another class which is responding to this event is defined as follows:
Class B{
public B(ParsedResult _result)
{
InitializeComponent();
if (_result != null)
{
this.Result = _result;
PopulateColumns1();
DataGrid1.Items.Clear();
DataGrid1.ItemsSource = Populatevariables();
}
}
public void PopulateColumns1()
{
DataGridTextColumn Colvar = new DataGridTextColumn();
Colvar.Header = "Variables";
Colvar.Binding = new Binding("Name");
DataGrid1.Columns.Add(Colvar);
DataGridTemplateColumn Col = new DataGridTemplateColumn();
Col.Header = "Select";
DataTemplate dd = new DataTemplate();
FrameworkElementFactory FF = new FrameworkElementFactory(typeof(CheckBox));
FF.SetBinding(CheckBox.BindingGroupProperty, new Binding("Select"));
FF.SetBinding(CheckBox.IsCheckedProperty, new Binding("IsSelected") { UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
FF.SetValue(FrameworkElement.HorizontalAlignmentProperty, HorizontalAlignment.Center);
dd.VisualTree = FF;
Col.CellTemplate = dd;
DataGrid1.Columns.Add(Col);
}
private List<A> PopulateVariables()
{
CheckBox cb = new CheckBox();
List<A> CharList = new List<A>();
Result.GetCharacteristicList.MoveNext();
IEnumerator<A2LCharacteristic> enumeratorlist = Result.GetCharacteristicList;
for (int i = 0; enumeratorlist.MoveNext(); i++)
{
CharList.Add(new A() { Name = enumeratorlist.Current.Name, Select = i, Formref1 = this});
}
enumeratorlist.Reset();
return CharList;
}
private void OKBtn_Click(object sender, RoutedEventArgs e)
{
A Instance_A = new A();
Instance_A.ThrowAddEvent += (sender1, args) => { Addvrbl(Instance_A.variable); };
Instance_A.ThrowRemoveEvent += (sender2, args) => { RmvVrbl(Instance_A.variable); };
this.Close();
}
public void Addvrbl(string vrbl)
{
if (!(vrbllist.Contains(vrbl)))
{
vrbllist.Add(vrbl);
}
}
public void RmvVrbl(string vrbl)
{
if ((vrbllist.Contains(vrbl)))
{
vrbllist.Remove(vrbl);
}
}
}
The problem is it is not going inside the method "AddVrbl" and "RmvVrbl". I have used the solution from here. Please help.
OK, instead of subscribing to the event of a new instance of A,which will never get triggered/published. When you initializing CharList, you have to subscribe to the event of each A item.
Something like:
for (int i = 0; enumeratorlist.MoveNext(); i++)
{
var obja=new A() { Name = enumeratorlist.Current.Name, Select = i, Formref1 = this};
obja.ThrowAddEvent += ...
obja.ThrowRemoveEvent += ...
CharList.Add(obja);
}
PS: Make sure you un-subscribe these events before removing an item from your CharList.

How to bind a combo box datasource to a form/listbox in windows forms?

I would like to get the form as datasource when i click combo box. How could i achieve this. Please give suggestion.
I've created a PopupComboBox class which inherits from the standard Windows Forms ComboBox. It has a Title property that you can set which will be used on the popup window when the combo is clicked.
public class PopupComboBox : ComboBox
{
private string title;
public string Title
{
get { return this.title; }
set { this.title = value; }
}
public PopupComboBox() : base()
{
}
public PopupComboBox (string title)
: base()
{
this.title = title;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
// Show the popup form
var popup = new SelectItemForm(this.title, this);
var result = popup.ShowDialog(this);
if (result == DialogResult.OK)
{
// Select this item in the ComboBox
SelectedIndex = this.FindStringExact(popup.SelectedDisplay);
}
}
}
When you click on the combo, a popup form will come up (source code below for SelectItemForm). It uses the DataSource, ValueMember and DisplayMember of the parent PopupComboBox to populate a ListView with the list of items from the combo. When you click on OK, it will save the selected item in the SelectedValue and SelectedDisplay properties so that we can select that item in the ComboBox when the form closes.
public partial class SelectItemForm : Form
{
public object SelectedValue { get; private set; }
public string SelectedDisplay { get; private set; }
public SelectItemForm(string title, PopupComboBox parent)
:base()
{
InitializeComponent();
this.Text = title;
// Add items to the list
foreach (var item in parent.Items)
{
// Get the display and value member properties for this combo box
// and use them for the Code/Name columns in the popup form
var props = item.GetType().GetProperties();
var code = props.Where(p => p.Name == parent.ValueMember).Single().GetValue(item);
var name = props.Where(p => p.Name == parent.DisplayMember).Single().GetValue(item);
listView.Items.Add(new ListViewItem(
new string[] { code.ToString(), name.ToString() }));
}
}
private void btnOk_Click(object sender, EventArgs e)
{
if (listView.SelectedItems != null && listView.SelectedItems.Count > 0)
{
SelectedValue = listView.SelectedItems[0].Text;
SelectedDisplay = listView.SelectedItems[0].SubItems[1].Text;
DialogResult = DialogResult.OK;
}
else
{
MessageBox.Show(this, "Select an item first", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}
Here is the designer part of the form, where you can see what properties I've changed for the ListView to look like it does:
partial class SelectItemForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.listView = new System.Windows.Forms.ListView();
this.btnOk = new System.Windows.Forms.Button();
this.btnCancel = new System.Windows.Forms.Button();
this.Code = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.Value = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader()));
this.SuspendLayout();
//
// listView
//
this.listView.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
this.Code,
this.Value});
this.listView.FullRowSelect = true;
this.listView.GridLines = true;
this.listView.Location = new System.Drawing.Point(3, 3);
this.listView.MultiSelect = false;
this.listView.Name = "listView";
this.listView.Size = new System.Drawing.Size(432, 170);
this.listView.TabIndex = 0;
this.listView.UseCompatibleStateImageBehavior = false;
this.listView.View = System.Windows.Forms.View.Details;
//
// btnOk
//
this.btnOk.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnOk.Location = new System.Drawing.Point(272, 179);
this.btnOk.Name = "btnOk";
this.btnOk.Size = new System.Drawing.Size(75, 23);
this.btnOk.TabIndex = 1;
this.btnOk.Text = "OK";
this.btnOk.UseVisualStyleBackColor = true;
this.btnOk.Click += new System.EventHandler(this.btnOk_Click);
//
// btnCancel
//
this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.btnCancel.Location = new System.Drawing.Point(353, 179);
this.btnCancel.Name = "btnCancel";
this.btnCancel.Size = new System.Drawing.Size(75, 23);
this.btnCancel.TabIndex = 2;
this.btnCancel.Text = "Cancel";
this.btnCancel.UseVisualStyleBackColor = true;
this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
//
// Code
//
this.Code.Text = "Code";
this.Code.Width = 108;
//
// Value
//
this.Value.Text = "Name";
this.Value.Width = 296;
//
// SelectItemForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(440, 214);
this.Controls.Add(this.btnCancel);
this.Controls.Add(this.btnOk);
this.Controls.Add(this.listView);
this.MaximizeBox = false;
this.MinimizeBox = false;
this.Name = "SelectItemForm";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Title";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.ListView listView;
private System.Windows.Forms.Button btnOk;
private System.Windows.Forms.Button btnCancel;
private System.Windows.Forms.ColumnHeader Code;
private System.Windows.Forms.ColumnHeader Value;
}
I've also created a small test form where you can test out the functionality of the PopupComboBox, using a small list of products. You'll need to add a PopupComboBox to the form in the designer, and call it comboPopup.
public partial class TestForm : Form
{
public class Product
{
public string Code { get; set; }
public string Name { get; set; }
}
public TestForm()
{
InitializeComponent();
}
private void TestForm_Load(object sender, EventArgs e)
{
var products = new List<Product>();
products.Add(new Product { Code = "0001", Name = "Coca Cola" });
products.Add(new Product { Code = "0002", Name = "Mountain Dew" });
products.Add(new Product { Code = "0003", Name = "Sprite Zero" });
comboPopup.DataSource = products;
comboPopup.DisplayMember = "Name";
comboPopup.ValueMember = "Code";
}
}

How to insert multiple data templates into main date template

I am using AvalonDock and MEF plugin architecture,
Each plugin returns a data template to host, host get the data template, insert to main data template.
Following are user controls that are converted to DataTemplates
MainMethodView: including a tab,
PluginA's MethodView: need to be inserted to MainMethodView's tab item 1.
PluginB's MethodView: need to be inserted to MainMethodView's tab item 2.
.....
Thanks.
Code: InitializePlugins() i have only could shows one plugin's datatemplate. and GetMethodViewTemplate() gives me error: Content of a ContentControl must be a single element.
reference: Link1
public void InitializePlugins(){
var templateSelector = new PanesTemplateSelector();
templateSelector.MethodViewTemplate = pluginService.Plugins[0].MethodViewTemplate;
_dockingManger.LayoutItemTemplateSelector = templateSelector;
}
private static DataTemplate GetMethodViewTemplate(PluginService pluginService) {
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(MethodView));
foreach (var plugin in pluginService.Plugins) {
FrameworkElementFactory fef = new FrameworkElementFactory(typeof(ContentControl));
fef.SetValue(ContentControl.ContentTemplateProperty, plugin.MethodViewTemplate);
factory.AppendChild(fef);
}
DataTemplate dt = new DataTemplate();
dt.VisualTree = factory;
return dt;
}
Another problem is databinding, MainMethodViewModel has PluginMethodViewModels from plugins, How it could be binded to MainMethodView.
This is the solution I found. Share everyone.
Note: View1 and View2 are usercontrol, binding setting is in xaml file.
public MainWindow() {
InitializeComponent();
CreateTemplate4();
}
private void CreateTemplate4() {
var method = new MethodViewModel();
FrameworkElementFactory fefWrapper = new FrameworkElementFactory(typeof(TabControl));
foreach (var fred in method.Freds) {
DataTemplate dt1 = fred.Template;
FrameworkElementFactory fefTop = new FrameworkElementFactory(typeof(ContentControl));
fefTop.SetValue(ContentControl.ContentTemplateProperty, dt1);
fefTop.SetValue(ContentControl.ContentProperty, fred);
fefWrapper.AppendChild(fefTop);
}
DataTemplate dtWrapper = new DataTemplate(typeof(MethodViewModel));
dtWrapper.VisualTree = fefWrapper;
this.DataContext = method;
this.cc.ContentTemplate = dtWrapper;
}
class MethodViewModel {
public ObservableCollection<Fred> Freds { get; set; }
public MethodViewModel() {
Freds = new ObservableCollection<Fred>();
Freds.Add(new Fred1(1));
Freds.Add(new Fred2(2));
}
}
public class Fred {
public int X { get; set; }
public int y { get; set; }
public Fred(int x) {
this.X = x;
this.y = x + 1;
}
public DataTemplate Template { get; set; }
}
public class Fred1 : Fred {
public Fred1(int x) : base(x) {
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(View1));
DataTemplate dt = new DataTemplate();
dt.VisualTree = factory;
this.Template = dt;
}
}
public class Fred2 : Fred {
public Fred2(int x) : base(x) {
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(View2));
DataTemplate dt = new DataTemplate();
dt.VisualTree = factory;
this.Template = dt;
}
}

silver light datagrid

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.

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