8 Replies - 3931 Views - Last Post: 01 February 2010 - 01:31 PM Rate Topic: -----

#1 Vermiculus   User is offline

  • D.I.C Regular
  • member icon

Reputation: 10
  • View blog
  • Posts: 314
  • Joined: 26-February 09

C# Custom Control Property...

Posted 31 January 2010 - 03:59 PM

Is it possible to set up a property of a custom control in such a way that it would be set in an interface similar to a datagridview? The ultimate goal is allow the user to see the glossary term and its corresponding definition at the same time... I have a working system in which I just have two string arrays, but considering the user, it would be exceedingly difficult to review the setting...

edit:
just thinking out loud...perhaps XML could be helpful here...

This post has been edited by Vermiculus: 31 January 2010 - 04:27 PM


Is This A Good Question/Topic? 0
  • +

Replies To: C# Custom Control Property...

#2 MentalFloss   User is offline

  • .
  • member icon

Reputation: 577
  • View blog
  • Posts: 1,500
  • Joined: 02-September 09

Re: C# Custom Control Property...

Posted 31 January 2010 - 07:18 PM

Quote

Is it possible to set up a property of a custom control in such a way that it would be set in an interface similar to a datagridview?


Can you please explain this better? I'm having a hard time with it.
Thanks.
Was This Post Helpful? 0
  • +
  • -

#3 Vermiculus   User is offline

  • D.I.C Regular
  • member icon

Reputation: 10
  • View blog
  • Posts: 314
  • Joined: 26-February 09

Re: C# Custom Control Property...

Posted 31 January 2010 - 08:43 PM

The only way I can explain it is some way for the end user of this control to be able to see like... well
column one would be terms and column two would be definitions, and you can enter as many terms and definitions as you want and have them be as long as you want (within the scope of the type of course), but each term must have a definition. In other words, the 'term' would be the key of a record (a definition).

Also, if there was no definition specified, optimally it would grab a string from its properties and set as such (a default definition).

Would some sort of graphic help?

This post has been edited by Vermiculus: 31 January 2010 - 08:43 PM

Was This Post Helpful? 0
  • +
  • -

#4 MentalFloss   User is offline

  • .
  • member icon

Reputation: 577
  • View blog
  • Posts: 1,500
  • Joined: 02-September 09

Re: C# Custom Control Property...

Posted 31 January 2010 - 09:00 PM

No. However, if you're going to go term,definition then I think you're going to run into a problem because there can be multiple definitions for a term. In such a case, your key is broken.

I'd imagine you need an actual auto-incrementing identity column for your term,definition pairs so that they really can stay separate. In that case, you can insert multiple terms and pull all definitions on a specific term without breaking the unique-ness of a term.
Was This Post Helpful? 0
  • +
  • -

#5 Vermiculus   User is offline

  • D.I.C Regular
  • member icon

Reputation: 10
  • View blog
  • Posts: 314
  • Joined: 26-February 09

Re: C# Custom Control Property...

Posted 31 January 2010 - 09:01 PM

For right now, the goal can be achieved with just one string/string combo. I will probably implement this functionality in Glossary 2.0, but this would get a little more complicated then I want this tutorial to be...at least for now :)

a graphic: http://i1023.photobu...ceptcapture.png
Posted Image

perhaps a datagridview was a bad analogy...

This post has been edited by Vermiculus: 31 January 2010 - 09:08 PM

Was This Post Helpful? 0
  • +
  • -

#6 MentalFloss   User is offline

  • .
  • member icon

Reputation: 577
  • View blog
  • Posts: 1,500
  • Joined: 02-September 09

Re: C# Custom Control Property...

Posted 01 February 2010 - 10:46 AM

Realistically though, terms can have multiple definitions and it's not that hard to address. Here - I coded you an example.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace GlossaryDemo
{
	class Program
	{
		static void Main(string[] args)
		{
			GlossaryCollection glossary = new GlossaryCollection();
			glossary.Add(new GlossaryEntry() { Id = 1, Term = "Simple", Definition = "easy to understand, deal with, use, etc." });
			glossary.Add(new GlossaryEntry() { Id = 2, Term = "Simple", Definition = "not elaborate or artificial" });
			glossary.Add(new GlossaryEntry() { Id = 3, Term = "Difficult", Definition = "not easily or readily done; requiring much labor, skill, or planning to be performed successfully; hard" });
			glossary.Add(new GlossaryEntry() { Id = 4, Term = "Difficult", Definition = "hard to understand or solve" });

			IEnumerable<GlossaryEntry> items = glossary.GetAllDefinitions("Simple");
			foreach (GlossaryEntry item in items)
			{
				Console.WriteLine("{0}: {1}", item.Term, item.Definition);
			}
		}
	}

	internal class GlossaryCollection : KeyedCollection<int, GlossaryEntry>
	{
		public IEnumerable<GlossaryEntry> GetAllDefinitions(string term)
		{
			return from entry in this
				   where entry.Term.ToLower() == term.ToLower()
				   select entry;

		}

		protected override int GetKeyForItem(GlossaryEntry item)
		{
			return item.Id;
		}
	}

	internal class GlossaryEntry
	{
		public int Id
		{ get; set; }

		public string Term
		{ get; set; }

		public string Definition
		{ get; set; }
	}
}



Here's output:

Quote

Simple: easy to understand, deal with, use, etc.
Simple: not elaborate or artificial


See, pretty easy right?

EDIT:

You know, quite frankly I'm not that happy about exposing the implementation of the collection so I've revised it so that the calling code has no idea about ID.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace GlossaryDemo
{
	class Program
	{
		static void Main(string[] args)
		{
			GlossaryCollection glossary = new GlossaryCollection();
			glossary.Add("Simple", "easy to understand, deal with, use, etc.");
			glossary.Add("Simple", "not elaborate or artificial");
			glossary.Add("Difficult", "not easily or readily done; requiring much labor, skill, or planning to be performed successfully; hard");
			glossary.Add("Difficult", "hard to understand or solve");

			IEnumerable<GlossaryEntry> items = glossary.GetAllDefinitions("Simple");
			foreach (GlossaryEntry item in items)
			{
				Console.WriteLine("{0}: {1}", item.Term, item.Definition);
			}
		}
	}

	internal class GlossaryCollection : KeyedCollection<int, GlossaryEntry>
	{
		private static int currentId = 0;
		

		public IEnumerable<GlossaryEntry> GetAllDefinitions(string term)
		{
			return from entry in this
				   where entry.Term.ToLower() == term.ToLower()
				   select entry;

		}

		public void Add(string term, string definition)
		{
			Add(new GlossaryEntry(GetNextId(), term, definition));
		}

		private int GetNextId()
		{
			int output = currentId;
			currentId++;
			return output;
		}

		protected override int GetKeyForItem(GlossaryEntry item)
		{
			return item.Id;
		}
	}

	internal class GlossaryEntry
	{
		public int Id
		{ get; set; }

		public string Term
		{ get; set; }

		public string Definition
		{ get; set; }

		public GlossaryEntry(int id, string term, string definition)
		{
			Id = id;
			Term = term;
			Definition = definition;
		}
	}
}



Hopefully this looks a bit better. I never really get it totally right on the first pass.

EDIT:

You're welcome to change the GetNextId() implementation to just:

		private int GetNextId()
		{
			return currentId++;
		}



I just personally prefer the other way.

This post has been edited by MentalFloss: 01 February 2010 - 11:07 AM

Was This Post Helpful? 0
  • +
  • -

#7 Vermiculus   User is offline

  • D.I.C Regular
  • member icon

Reputation: 10
  • View blog
  • Posts: 314
  • Joined: 26-February 09

Re: C# Custom Control Property...

Posted 01 February 2010 - 11:57 AM

I certainly have alot to learn..

Can you explain what is going on here?
internal class GlossaryCollection : KeyedCollection<int, GlossaryEntry>
	{
		private static int currentId = 0;

		public IEnumerable<GlossaryEntry> GetAllDefinitions(string term) {
			return from entry in this
				   where entry.Term.ToLower() == term.ToLower()
				   select entry;
		}

		public void  Add(string term, string definition) {
			Add(new GlossaryEntry(GetNextId(), term, definition));
		}

I've never worked with an IEnumerable before, or really any true database, and the MSDN docs seem like gibberish... o_o
And why does that Add function work? Certainly alot to learn....

EDIT:
I have a feeling this is going to be another world-changing piece of knowledge.. right up there with OOP and ravioli.

This post has been edited by Vermiculus: 01 February 2010 - 12:10 PM

Was This Post Helpful? 0
  • +
  • -

#8 MentalFloss   User is offline

  • .
  • member icon

Reputation: 577
  • View blog
  • Posts: 1,500
  • Joined: 02-September 09

Re: C# Custom Control Property...

Posted 01 February 2010 - 12:28 PM

Certainly.

So, the way I used to work with collections was to use Lists and Dictionaries. However, I recently learned about a beautiful abstract class called KeyedCollection<K,V>. So, in order to use it, you create your collection and extend KeyedCollection<K,V> which is what I did here:

internal class GlossaryCollection : KeyedCollection<int, GlossaryEntry>



To be honest, I love this thing. What happens is you get sort of a hybrid between a list and a dictionary. You can add elements and the element itself has a key value. So, with extending that abstract class, you have to implement the abstract method GetKeyForItem(). Which is what this is:

protected override int GetKeyForItem(GlossaryEntry item)
{
	return item.Id;
}



Now, since the collection has to manage a type, I created the class that will contain the entries and just called it GlossaryEntry

internal class GlossaryEntry
	{
		public int Id
		{ get; set; }

		public string Term
		{ get; set; }

		public string Definition
		{ get; set; }

		public GlossaryEntry(int id, string term, string definition)
		{
			Id = id;
			Term = term;
			Definition = definition;
		}
	}



That's after my edit. You'll notice that the constructor takes the id, the term, and the definition. In regards to calling code though, it's kind of expected that the user will work with the collection instead of individual entries. So, I changed the collection class to be aware of the keys instead of forcing calling code to provide one that might already be in use.

private int GetNextId()
{
	int output = currentId;
	currentId++;
	return output;
}



With this, there's no need for calling code to have any knowledge of the ID.

Now, if you remember, the KeyedCollection is like a List and a Dictionary rolled into one. It has an Add() method to it.

Originally, I simply added directly in Main().

glossary.Add(new GlossaryEntry() { Id = 1, Term = "Simple", Definition = "easy to understand, deal with, use, etc." });



But, I really didn't like this way. So, on the collection class, I created an Add() method that is passed only the information I need (term and definition) and then it adds it via the KeyedCollection's Add() method after it has created a valid GlossaryEntry.

public void  Add(string term, string definition) 
{
	Add(new GlossaryEntry(GetNextId(), term, definition));
}



Since I need the next Id, I call GetNextId() to retrieve that. Also, since this is a new GlossaryEntry, I'm passing this information to the constructor:

public GlossaryEntry(int id, string term, string definition)
{
	Id = id;
	Term = term;
	Definition = definition;
}



Alright, so that should cover all the basic stuff. Let me talk about that method you asked about.

IEnumerable<T> is an interesting interface. It allows you to enumerate over a collection (in this case it's GlossaryEntry). The really cool thing though is that IEnumerable<T> is LINQ aware. In fact, it's essentially a foundation of LINQ. Anyway, here's that method:

public IEnumerable<GlossaryEntry> GetAllDefinitions(string term)
{
	return from entry in this
			 where entry.Term.ToLower() == term.ToLower()
			 select entry;

}



So, what I'm doing there is enumerating over the collection and searching for when the term matches the passed in term. If you notice, the target is "this". That's because this class is extending KeyedCollection so I am enumerating over this actual instance. Anyway, whatever it finds, it returns an IEnumerable<GlossaryEntry> collection. From there, I can enumerate over it myself and print the results:

foreach (GlossaryEntry item in items)
{
	Console.WriteLine("{0}: {1}", item.Term, item.Definition);
}



Pretty cool huh?

Any other questions? I hope I snagged them all.
Was This Post Helpful? 1
  • +
  • -

#9 Vermiculus   User is offline

  • D.I.C Regular
  • member icon

Reputation: 10
  • View blog
  • Posts: 314
  • Joined: 26-February 09

Re: C# Custom Control Property...

Posted 01 February 2010 - 01:31 PM

Very cool! I'll have to do more research on Collections in C#, but this looks like an exceedingly powerful tool. Thanks!
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1