I'am working in a GTK-sharp application. I have this code but combobox1 doesn't display any item. Why not?
ListStore store = new ListStore(typeof(myclass));
store.AppendValue(new myclass("hola",7));
store.AppendValue(new myclass("hola2",8));
store.AppendValue(new myclass("hola3",2));
combobox1.Model = store;
The class myclass overrides ToString()
What you are looking for is custom Gtk.CellRenderer:
private void MyClassRenderer(CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter)
{
MyClass myclass = model.GetValue(iter, 0) as MyClass;
(cell as CellRendererText).Text = myclass.ToString();
}
With some additional code in the setup method like this:
CellRendererText myClassCell = new CellRendererText();
combobox1.PackStart(myClassCell, true);
combobox1.SetCellDataFunc(myClassCell, MyClassRenderer);
ListStore store = new ListStore(typeof(MyClass));
store.AppendValues(new MyClass("hola",7));
store.AppendValues(new MyClass("hola2",8));
store.AppendValues(new MyClass("hola3",2));
combobox1.Model = store;
Make sure the SetCellDataFunc method is called after PackStart method.
Job done! :)
I'm not really sure, but make sure the listbox key and values are mapped to the fields in the class. I think it needs to be specific. After setting the value, make sure to do the final databind like: control.DataBind();
In general, C# binding goes like: 1) automatic colum generation/manually map all fields to keys and values 2). set the field 3. and call the bind() function.
Related
I am using MVP in my project, but i am new in MVP.
I have two comboboxes. When I select an option in a combobox, the another combobox should be filled with new data.
This action will be in Presenter. I get my view 'view1' in Presenter, and introduced Combobox1 and Combobox2 as properties in 'view1', because I need 'DataSource', 'DisplayMember', 'ValueMember' and 'Refresh()' in the method below.
But, when using a pattern, it is enough to send a property like
public string Combobox2
{
get { return comboBox1.SelectedValue.ToSstring(); }
}
into Presenter not the whole Combobox. How can I solve this problem?
public void OnSelectedIndexChangedCombobox1()
{
if (view1.Combobox1.SelectedIndex == -1)
{
return;
}
DataTable dt = Tools.GetDataTable("A Path");
var query =
(from o in dt.AsEnumerable()
where o.Field<string>("afield") ==
farmerView.Combobox1.SelectedValue.ToString()
orderby o.Field<string>("anotherfield")
select new KeyValuePair<string, string>(o.Field<string>("field1"),
o.Field<string>("field2"))).ToList();
farmerView.Combobox2SelectedIndexChanged -= OnSelectedIndexChangedCombobox2;
farmerView.Combobox2.DataSource = new BindingSource(query, null);
farmerView.Combobox2.DisplayMember = "Value";
farmerView.Combobox2.ValueMember = "Key";
farmerView.Combobox2.Refresh();
farmerView.Combobox2SelectedIndexChanged +=
OnSelectedIndexChangedCombobox2;
farmerView.Combobox2.SelectedIndex = -1;
}
Thank you
You should not pass any Android objects to presenter, just get the event in view (for instance your Activity) then call a method from presenter that provides data for second ComboBox (we call it Spinner in Android!) by passing selected item from first one, and then presenter will call a method of View which fill the second one and View knows how to do it.
You can take a look at this sample project http://github.com/mmirhoseini/marvel and this article https://hackernoon.com/yet-another-mvp-article-part-1-lets-get-to-know-the-project-d3fd553b3e21 to get more familiar with MVP.
I have an object that I have bound to a control on a form using C# WinForms (targetting .NET 4.5.2). I have implemented INotifyPropertyChanged, and when I modify a Property of this object, it updates on the Form's control as expected. However, when I change this object's instance to a new instance, it will no longer update the control, even if I try to modify a specific Property.
class User : INotifyPropertyChanged
{
string _name = "";
public string Name
{
get { return _name; }
set { _name = value; OnPropertyChanged("Name"); }
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public User() { }
public User(string name)
{
Name = name;
}
public User(User otherUser)
{
Name = otherUser.Name;
}
}
and on the Form I have
User currentUser = new User("Example Name");
lblName.DataBindings.Add("Text", currentUser, "Name");
which updates properly. I can change name using currentUser.Name = "Blahblah"; and it works fine. When I try to call currentUser = new User("New Name");, it will no longer update no matter what I do.
It is my understanding that the specific instance of the object is what the controls are bound to. My primary goal is to not have to manually go through each Property of larger objects and manually change everything over every single time I want to change instances.
My question: is there a way to change instances of an object without removing the binding to the control?
To get the desired behavior, you should not bind directly to the concrete instance like you do currently:
lblName.DataBindings.Add("Text", currentUser, "Name");
Instead, you need some intermediary. The easiest is to use the BindingSource component for that purpose.
Add a BindingSource field to the form:
private BindingSource dataSource;
Then initialize it and bind the controls to it one time (usually in form Load event):
dataSource = new BindingSource { DataSource = typeof(User) };
lblName.DataBindings.Add("Text", dataSource, "Name");
// ...
Now anytime you want to bind to a User instance, you simply assign it to the DataSource property of the BindingSource:
initial:
dataSource.DataSource = new User("Example Name");
later:
dataSource.DataSource = new User("New Name");
Ivan showed you how to solve the problem. Here in this answer I'll try to show you what the problem is and why it works this way.
Short answer
Your label is bound to an object not the variable. The variable is just like a pointer to the object. So replacing the variable doesn't have any impact on the object which your label is using as data source. Just the variable points to the new object. But your label is using the previous object. It has its own pointer to the previous object.
Consider these facts to know what is happening:
User currentUser = new User("Example Name");
When you assign an object to a variable, in fact the variable points to the object.
lblName.DataBindings.Add("Text", currentUser, "Name");
You performed data-binding to the object. The control will be bound to the object not the variable.
currentUser.Name = "Blahblah";
You changed the value of Name property and since you implemented INotifyPropertyChanged the control will be notified of changes and will refresh its Text.
But the main statement which didn't work as you expected:
currentUser = new User("New Name");
Here you made the currentUser variable point to another object. It doesn't have anything to do with the previous object which it was pointing to. It just points to another object.
The Binding which you added to the label, still uses the previous object.
So it's normal to not have any notification, because the object which is in use by the label didn't changed.
How the BindingSource solved the problem?
The BindingSource raises ListChanged event when you assign a new object to its DataSource and it makes the BindingObject fetch new value from DataSource and refresh Text property. You can take a look at this post: How to make a binding source aware of changes in its data source?
I have a listview (lvMap) with 3 columns (Map, From, To) I am trying to write a method that is called as soon as my form loads. this method should look at the listview items and and sort them only by 2 columns "Map" and "From" in ascending order, i dont want it to sort the "To" column. I have written the code below but it sorts every single column, is there a way to leave a column out of the sorting procedure. Thanks.
private void sortListViewOrder()
{
lvMappings.Sorting = SortOrder.Ascending;
lvMappings.Sort();
}
I would suggest you consult the following MSDN article, hopeful it answers your question:
http://support.microsoft.com/kb/319401
Basically you need to create a ListViewColumnSorter instance and add it to your ListView control.
From there on the article will have enough information :)
You have to do it using ListViewColumnSorter . Following KB Link has the sample code to do that.
http://support.microsoft.com/kb/319401
You can assign the column to be sorted using,
Create an instance of a ListView column sorter and assign it
// to the ListView control.
lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;
lvwColumnSorter.SortColumn = Column;
I needed this feature, or function, in the ListView control. The suggestion to use an Extension Class I first saw here. I tried it and it worked, but only now I can tell how to easily do it. Refer to this reference question:
How to prevent flickering in ListView when updating a single ListViewItem's text?
Step 1: Create a (separate) ControlExtensions class in your project, and paste this code:
using System.Reflection;
using System.Windows.Forms;
namespace [YourNameSpace]
{
public static class ControlExtensions
{
public static void DoubleBuffering(this Control control, bool enable)
{
var method = typeof(Control).GetMethod("SetStyle", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(control, new object[] { ControlStyles.OptimizedDoubleBuffer, enable });
}
}
}
Step 2: Define the following in the WinForms that has the ListView:
private ListViewColumnSorter lvwColumnSorter = null;
After InitializeComponent(); section, define the following:
lvwColumnSorter = new ListViewColumnSorter();
this.lvwRunningProcesses.ListViewItemSorter = lvwColumnSorter;
lvwColumnSorter._SortModifier = ListViewColumnSorter.SortModifiers.SortByText;
Step 3: In the Form Load event, add these lines after the List View is populated:
// Sort in ascending order Column 0
lvwColumnSorter.SortColumn = 0;
lvwColumnSorter.Order = SortOrder.Ascending;
this.lvwRunningProcesses.Sort();
That's it!
I am trying to write a function as follows:
private void Func1(DataColumnChangeEventArgs e)
{
ds.TableName.AddRow(
e.Row[e.Column.ColumnName, DataRowVersion.Original].ToString(),
e.Row[e.Column.ColumnName, DataRowVersion.Proposed].ToString());
}
and I am calling it as:
private void Func2()
{
DataColumnChangeEventArgs e = new DataColumnChangeEventArgs(
dataTable.Rows[index],
dataTable.Columns["ColName"],
newValue);
e.ProposedValue = newValue;
Func1(e);
}
However, e.Row[e.Column.ColumnName, DataRowVersion.Proposed].ToString() is throwing a VersionNotFoundException. Is there any way to achieve this?
I would say, your method should look like this:
ds.TableName.AddRow(e.Row[e.Column.ColumnName].ToString(), e.ProposedValue.ToString());
As there is no versions in that row in your row in args, but there is new and old values...
DataColumnChangedEventArgs is designed to be used with a class like DataTable. The DataTable creates an instance when calling the associated events (like ColumnChanged). Creating an instance of one will not actually create the change to the data row.
The e.ProposedValue = newValue is redundant, you already gave the newValue in the constructor.
You can access the value through e.ProposedValue. So through this system you can only make one change to the row at a time and you must remember which column it was.
I'm trying to update textedit control through the Client class object databindings with INotifyPropertyChanged implementation and i can't get it to work. The object behind (datasource) updates but the textedit still remains blank. If i type the text into the editbox the datasource gets updated. Would you help please? Here's the relevant code i'm using:
public class Client : NotifyProperyChangedBase
{
private string _firstname;
public string Firstname
{
get
{
return this._firstname;
}
set
{
this.CheckPropertyChanged<string>("Firstname", ref _firstname, ref value);
}
}
}
public Client ClientA = new Client();
Binding fname = new Binding("Text", ClientA, "Firstname", true, DataSourceUpdateMode.OnPropertyChanged);
ultraTextEditor_firstname.DataBindings.Add(fname);
ClientA.Firstname = "testN"; <== editbox remains blank ...
Am I missing something here? Thanks in advance, Peter.
I am assuming your base is implemented something along the lines of this example. If I am incorrect in my assumption, you will need to provide the implementation of your NotifyProperyChangedBase class.
You may also want to review the Binding(String, Object, String, Boolean, DataSourceUpdateMode) constructor documentation, as it discusses the control events the binding attempts to locate.
Looking at that example, you will want to try something like this:
System.ComponentModel.BindingList<Client> bindings = new System.ComponentModel.BindingList<Client>();
Client clientA = bindings.AddNew();
clientA.Firstname = "John";
textEditControl.DataSource = bindings;
// This change presumably will be refelected in control
clientA.Firstname = "Jane";
Update:
After reviewing the documentation on the Add method of the ControlBindingsCollection class; I believe that the data source of the Binding needs to implement the IListSource interface in order to properly participate in the binding (all MSDN examples are DataSet or DataTable which implement this interface).