WPF ComboBox Databound to a class - c#

Should it be possible to bind a WPF combo box to a class. I have a class that implements IEmunerable and IEnumerator, and contains a list of objects, as follows:
class MyClass
{
public string Title { get; set; }
public string Directory { get; set; }
public MyClass(string title, string directory)
{
Title = title;
Directory = directory;
}
}
class MyClasses : IEnumerable, IEnumerator
{
private List<MyClass> allClasses;
private int position = 0;
public List<MyClass> GetClasses()
{
allClasses = new List<MyClass>()
{
new MyClass("example1", "dir1"),
new MyClass("example2", "dir2")
};
return allClasses;
}
public IEnumerator GetEnumerator()
{
return (IEnumerator) this;
}
public object Current
{
get
{
return allClasses[position];
}
}
public bool MoveNext()
{
position++;
return (position < allClasses.Count());
}
public void Reset()
{
position = -1;
}
}
So now I want to bind this to a WPF combobox. Here’s what I have, which doesn’t work (I instead get a list of type names of the objects):
allClasses.GetClasses();
cboTest.ItemsSource = allClasses;
cboTitle.SelectedValue = "Title";
Can anyone tell me how to implement this binding?

cboTitle.SelectedValue = "Title";
should be
cboTitle.DisplayMemberPath = "Title";

Change
cboTitle.SelectedValue = "Title";
to
cboTitle.DisplayMemberPath = "Title";

Related

checking if datagrid has values

I am working on a C# project which includes WPF. I was wondering, If I could somehow check If my data grid contains certain element.
For example,
I have combo box whose itemsSource is some list of objects. Now, when an user selects an item from the combo box and presses the button
below in data grid (in same window) that item shows up.
I want to forbid the user to select same item more than once and for example put MessageBox with error message. How could I do that?
Code
This Window:
public partial class AvioWindowAddNEdit : Window
{
Avio avio;
public enum Stage { ADD, EDIT};
Stage stage;
public AvioWindowAddNEdit(Avio avio, Stage stage = Stage.ADD)
{
InitializeComponent();
this.avio= avio;
this.stage= stage;
textboxCode.DataContext = avio;
comboboxListofFlights.ItemsSource = Aplikacija.Instance.Flights;
comboboxListofFlights.DataContext = avio;
datagridListofFlights.ItemsSource = avio.ListofFlights;
datagridListofFlights.ColumnWidth = new DataGridLength(1, DataGridLengthUnitType.Auto);
if (stage== Stage.EDIT)
{
textboxCode.IsEnabled = false;
}
}
}
Button which adds selected item to data grid:
private void btnAddFlight_Click(object sender, RoutedEventArgs e)
{
avio.ListOfFlights.Add(comboboxListOfFlights.SelectedItem as Flight);
}
Singleton class for loading in all of my data:
class Aplication
{
public ObservableCollection<User> Users { get; set; }
public ObservableCollection<Airport> Airports { get; set; }
public ObservableCollection<Flight> Flights{ get; set; }
public ObservableCollection<Avio> Avios { get; set; }
public string LoggedInUser { get; set; }
private static Aplication instance = new Aplication();
public static Aplication Instance
{
get
{
return instance;
}
}
private Aplication()
{
Users= new ObservableCollection<User>();
Airports = new ObservableCollection<Airport>();
Flights = new ObservableCollection<Flight>();
Avios= new ObservableCollection<Avio>();
FillInData(); //method where I filled in all of these ObservableCollections
}
}
My class:
public class Avio : ObservableObject, ICloneable
{
//observableobject is an object where I implemented INotifyPropertyChanged
private string code;
public string Code
{
get { return code; }
set { code= value; OnPropertyChanged("Code"); }
}
private ObservableCollection<Flight> listOfFlights;
public ObservableCollection<Flight> ListOfFlights
{
get { return listOfFlights; }
set { listOfFlights= value; OnPropertyChanged("ListOfFlights"); }
}
private bool active;
public bool Active
{
get { return active; }
set { active= value; OnPropertyChanged("Active"); }
}
public Avio()
{
active= true;
ListOfFlights = new ObservableCollection<Flight>();
}
public Avio(string code)
{
active= true;
ListOfFlights = new ObservableCollection<Flight>();
Code= code;
}
}
You could use an ObservableCollection as an ItemsSource for your DataGrid. In that way you'll always have easy access to the data via code.
Check out this tutorial as a starting point (this uses ListBox instead of DataGrid, but it's easily adaptable to DataGrid).

how to add object directly to nested ienumerable collection object group by Error- Cannot convert List to Collection

Hi I have created few nested iEnumerable implemented classes.
CDSWorkflowCollection
CDSModuleCollection
CDSSystemCollection
Below are my Classes
public class cdssystems
{
public string cdsSystemName;
public CDSModuleCollection listModules;
}
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
class cdsdelgate
{
private string delgateName;
private DateTime fromDate;
private DateTime toDate;
private string functionElement;
private CDSSystemCollection cdsSystemsList;
private string cdsComments;
private string JobTitle;
}
public class cdsworkflows
{
public string WorkflowName;
public string ActionGroup;
}
class CDSWorkflowCollection : ICollection, IEnumerable<cdsworkflows>
{
private List<cdsworkflows> cdsWorkflowList;
private readonly object syncObject = new object();
public CDSWorkflowCollection(IEnumerable<cdsworkflows> cdsWorkflowList)
: base()
{
this.cdsWorkflowList = new List<cdsworkflows>(cdsWorkflowList);
}
public IEnumerator<cdsworkflows> GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.cdsWorkflowList.GetEnumerator();
}
public void CopyTo(Array array, int index)
{
if ((array.Rank != 1) || ((this.Count + index) > array.Length))
{
throw new ArgumentException();
}
int count = 0;
foreach (cdsworkflows cssWorkflow in this.cdsWorkflowList)
{
array.SetValue(cssWorkflow, count++);
}
}
public int Count
{
get
{
return this.cdsWorkflowList.Count;
}
}
public bool IsSynchronized
{
get
{
return false;
}
}
public object SyncRoot
{
get
{
return this.syncObject;
}
}
}
class CDSSystemCollection : ICollection, IEnumerable<cdssystems>
{
private List<cdssystems> cdsSystemList;
private readonly object syncObject = new object();
public CDSSystemCollection(IEnumerable<cdssystems> cdsSystemList)
: base()
{
this.cdsSystemList = new List<cdssystems>(cdsSystemList);
}
//Rest of the code here
}
class CDSDelegateCollection : ICollection, IEnumerable<cdsdelgate>
{
private List<cdsdelgate> cdsDelegateist;
private readonly object syncObject = new object();
public CDSDelegateCollection(IEnumerable<cdsdelgate> cdsDelegateList)
: base()
{
this.cdsDelegateist = new List<cdsdelgate>(cdsDelegateList);
}
//Rest of the code here
}
No i want to add objects to the class using group by and my code goes like below
var results = (from SPListItem item in myItemsList
group item by item["Systems"]
into grp
select new cdssystems()
{
cdsSystemName = grp.Key.ToString(),
listModules = (from item in grp
group item by item["Modules"]
into grpModules
select new cdsmodules()
{
moduleName = grpModules.Key.ToString(),
listWorkflows = (from item in grpModules
group item by item["Workflows"]
into grpWorkflows
select new cdsworkflows()
{
WorkflowName = grpWorkflows.Key.ToString(),
ActionGroup = grpWorkflows.FirstOrDefault()["ActionGroup"].ToString()
}
).ToList()
}).ToList()
}).ToList();
I am getting Error in ToList() saying
Cannot implicitly convert type 'System.Collections.Generic.List' to 'CDS.BusinessObjects.CDSWorkflowCollection'
I know the parm expects a collection and i am passing List. How to pass the collection. Please help
Delete your custom collection types and use the Generic ones from the .net framework instead. You can use List<T>, IList<T>, or ICollection<T>. There is almost never a need to write your own collection implementation(s).
public class cdsmodules
{
public string moduleName;
public CDSWorkflowCollection listWorkflows;
}
becomes
public class cdsmodules
{
public string moduleName { get; set; }
public List<cdsworkflows> listWorkflows { get; set; }
}
You should also follow proper visibility guidelines by never exposing fields directly. Instead use a property with a get;set; accessor. Fields should almost always be scoped as private or protected.

How do I convert BindingSource.DataSource to my custom object?

I have a custom dataset style class defined as:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
namespace LibrarySort.Data
{
public class LibraryData
{
private AlbumList albums;
public AlbumList Albums { get { return albums; } }
public LibraryData()
{
this.albums = new AlbumList();
this.albums.AllowEdit = true;
this.Albums.AllowNew = true;
this.Albums.AllowRemove = true;
}
public void FillAll()
{
this.Albums.Fill();
}
}
public class AlbumList : BindingList<Album>
{
public AlbumList()
{
}
public void Fill()
{
int id = 1;
Album album1 = new Album();
album1.Id = id++;
album1.Artist = "Classical Piano Artist";
album1.Download = true;
album1.Person = null;
album1.Price = (decimal?)3.49;
album1.Tags.Add("classical");
album1.Tags.Add("piano");
album1.Title = "Classical Piano";
Album album2 = new Album();
album2.Id = id++;
album2.Artist = "Thrash Metal Artist";
album2.Download = false;
album2.Person = null;
album2.Price = (decimal?)7.99;
album2.Tags.Add("thrash metal");
album2.Title = "Thrash Metal";
this.Items.Add(album1);
this.Items.Add(album2);
}
}
}
I also a have Form object that inside a TabControl has a DataGridView. In the designer, I created a BindingSource and used the Add Project Data Source to create a source from the top level LibraryData object. I then bind the DataGridView to the "Albums" data member, all in the designer, and the columns get populated in the designer as expected.
When running the code, the table isn't populated, which makes sense as the Fill() hasn't been run. So I create a Load event handler for the form as follows:
private void MainForm_Load(object sender, EventArgs e)
{
LibraryData data = (LibraryData)bindingSource.DataSource;
data.FillAll();
}
However on run I get the following in MainForm_Load():
System.InvalidCastException was unhandled
Message="Unable to cast object of type 'System.RuntimeType' to type 'LibrarySort.Data.LibraryData'
I've Googled extensively on this, and in StackOverflow but no luck. Am I missing something?
Update: DataSource is definitely non-null. Also interestingly, in the designer code I see this:
this.bindingSource.DataSource = typeof(LibrarySort.Data.LibraryData);
Update 2: Album class and parent Item:
namespace LibrarySort.Data
{
public class Album : Item
{
bool download = false;
public bool Download { get { return download; } set { download = value; } }
string artist = null;
public string Artist { get { return artist; } set { artist = value; } }
}
}
namespace LibrarySort.Data
{
public class Item
{
int id = -1;
public int Id { get { return id; } set { id = value; } }
// FK to Person that currently has possession of item
int? person = null;
public int? Person { get { return person; } set { person = value; } }
string title = null;
public string Title { get { return title; } set { title = value; } }
decimal? price = null;
public decimal? Price { get { return price; } set { price = value; } }
State state = State.Owned;
public State State { get { return state; } set { state = value; } }
List<string> tags = null;
public List<string> Tags
{
get
{
if (tags == null)
tags = new List<string>();
return tags;
}
// No set needed
}
}
}
I think the issue is that although you have a binding source on your form, you have not set the datasource of the binding source.
Assuming that bindingSource is the datasource you dropped on your form, then try the following in the MainForm_Load:
LibraryData data = new LibraryData();
data.FillAll();
bindingSource.DataSource = data;

How to select index in listbox

I display string array as listbox in property grid with type converter with code as follow.
How to select index of listbox for initialize first time program loaded? I want SelectedIndex = 0, show first arrData = "one". Any Idea?
public partial class Form1 : Form
{
string[] arrData = new string[] { "one", "two", "three" };
PropertyGrid pGrid = new PropertyGrid();
public Form1()
{
InitializeComponent();
FirstClass fClass = new FirstClass(arrData);
pGrid.SelectedObject = fClass;
pGrid.Dock = DockStyle.Fill;
this.Controls.Add(pGrid);
}
public class FirstClass
{
public FirstClass(string[] arrData)
{
this.DataSource = arrData;
}
[Browsable(true)]
[DefaultValue("one")]
[TypeConverter(typeof(SecondClass))]
public string Counter { get; set; }
[Browsable(false)]
public string[] DataSource { get; set; }
}
public class SecondClass : StringConverter
{
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
FirstClass fClass = (FirstClass)context.Instance;
if (fClass == null || fClass.DataSource == null)
{
return new StandardValuesCollection(new string[0]);
}
else
{
return new StandardValuesCollection(fClass.DataSource);
}
}
}
}
If I understood you right it should be as easy as this code below if you just want to set the index of the selected item in an listbox to 0.
ListBox.SelectedIndex = 0;
For further details, please check out the MSDN page.
http://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.selectedindex.aspx

How can i save my listbox to ObservableCollection<>

MyDoc.cs
public class MyDoc
{
public string Private {set;get;}
public string Public {set;get;}
}
MyFind.cs
public class MyFind
{
public string Find {set;get;}
public string News {set;get;}
private ObservableCollection<MyDoc> _list;
public ObservableCollection<MyDoc> List
{
get
{
if (_list == null)
{
_list = new ObservableCollection<MyDoc>();
}
return _list;
}
set
{
if (_list != value)
{
_list = value;
}
}
}
}
In Page1.xaml.cs
MyFind myfind = new MyFind();
myfind.Find = Findtextbox.Text;//string = string
myfind.News = Newstextbox.Text;//string = string
myfind.List = ???
ObservableCollection = listbox1.??? (??? = Items,or ItemsSources,or something,...May I use Convert ?)<------------ I don't have any ideas ! Help me !
If you've set the ItemsSource property to something like a List you could execute the following code:
MyFind myFind = new MyFind();
var myDocs = simpleListBox.ItemsSource as List<MyDoc>;
myDocs.ForEach(d => myFind.List.Add(d));
I think you're looking for the ItemsSource property:
MyFind myfind = new MyFind();
myfind.Find = Findtextbox.Text;
myfind.News = Newstextbox.Text;
myfind.List = new ObservableCollection<MyDoc>(listbox1.ItemsSource.Cast<MyDoc>());
Here I'm creating a new ObservableCollection of MyDoc objects, and to the constructor I'm passing an IEnumerable of MyDoc items. Because the listbox1.ItemsSource property returns an untyped IEnumerable, I'm first casting it using LINQ to the correct type.
Why do you want to do this is just beyond me! If you use an ObservableCollection with Binding and add remove T (items) from your listbox, the observable collection will get updated. Something inline with this:
public class MyViewModel
{
public ObservableCollection<MyData> List { get; set; }
}
public class MyView : UserControl
{
public MyView()
{
DataContext = new MyViewModel();
}
}
<ListBox ItemsSource="{Binding List}" />

Categories

Resources