how to add item collection to trackbar in winforms - winforms

I have a track bar in the form. I want to map the track bar value with collection of string. Like items in the combo-box.
I can do this with separate collection by using the track bars value as index to the collection.
Is there a better way to do this.

you can customize yourself, like this:
public class MyTrackBar : TrackBar
{
public MyTrackBar()
{
InitItems(Maximum);
}
private void InitItems(int count)
{
Items = new List<string>(Maximum);
for (int i = 0; i < Maximum; i++)
{
Items.Add("Item" + i); // or any text, or empty.
}
}
public new int Maximum
{
get { return base.Maximum; }
set
{
base.Maximum = value;
InitItems(value);
}
}
public List<string> Items { get; private set; }
public string TextValue
{
get { return Items[Value]; }
}
public void ChangeText(int index, string text)
{
// ...
Items[index] = text;
}
}

Related

TreeView Populating / Binding

I created a parser that reads files formatted in the following way:
version="v4.5.32"
name="Test File"
date="2513.04.02"
players=
{
{
first_name="John"
last_name="Smith"
country=12
id=0
}
{
first_name="Mario"
last_name="Rossi"
country=56
id=1
}
}
next_player_id=2
matches=
{
22 47 88 1045 1048 3511
}
settings=
{
match_prefix="game"
match_reward_scalar=1,55
match_sets_points=
{
0,5 0,75 1,0
}
next_event_id=56
next_event_fired=false
next_event_probability=0,33
}
...
Basically, those files contain a list of key/value pairs in which keys are always a string and values can be either a simple value (boolean, date, float, integer, string), a record (a sublist of key/value pairs like settings) or an array (composed by simple values like matches or records like players). In order to parse and handle those values I created 3 simple classes.
1) MyPair
public sealed class MyPair
{
public MyKey Key { get; }
public MyValue Value { get; }
public MyPair(MyKey key, MyValue value) { ... }
public override String ToString()
{
return String.Concat(Key, " = ", Value);
}
}
2) MyKey
public sealed class MyKey
{
public String Name { get; }
... // other properties set by checking the name in the constructor
public Key(String name) { ... }
public override String ToString()
{
return Name;
}
}
3) MyValue
public sealed class MyValue
{
private readonly dynamic m_UnderlyingValue;
private readonly MyValueCategory m_Category;
public dynamic UnderlyingValue
{
get { return m_UnderlyingValue; }
}
public Boolean Container
{
get { return ((m_Category == ValueCategory.Array) || (m_Category == ValueCategory.Record)); }
}
public MyValueCategory Category
{
get { return m_Category; }
}
public MyValue(DateTime underlyingValue)
{
if (underlyingValue == null)
throw new ArgumentNullException("underlyingValue");
m_UnderlyingValue = underlyingValue;
m_Category = MyValueCategory.DateTime;
}
public MyValue(Boolean underlyingValue) { ... }
public MyValue(Double underlyingValue) { ... }
public MyValue(Int64 underlyingValue) { ... }
public MyValue(MyPair[] underlyingValue) { ... }
public MyValue(MyValue[] underlyingValue) { ... }
public MyValue(String underlyingValue) { ... }
public override String ToString()
{
switch (m_Category)
{
case MyValueCategory.Array:
return String.Concat("Array[", m_UnderlyingValue.Length, "]");
case MyValueCategory.Boolean:
return String.Concat("Boolean[", (m_UnderlyingValue ? "true" : "false"), "]");
case MyValueCategory.DateTime:
return String.Concat("DateTime[", m_UnderlyingValue.ToString("yyyy.MM.dd", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Float:
return String.Concat("Float[", m_UnderlyingValue.ToString("F3", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Integer:
return String.Concat("Integer[", m_UnderlyingValue.ToString("F0", CultureInfo.InvariantCulture), "]");
case MyValueCategory.Record:
return String.Concat("Record[", m_UnderlyingValue.Length, "]");
default:
return String.Concat("Text[", m_UnderlyingValue, "]");
}
}
}
public enum MyValueCategory
{
Array,
Boolean,
DateTime,
Float,
Integer,
Record,
Text
}
The parsing process works like a charm and returns me a MyValue instance that works like a container / root node for everything I parsed.
I'm not using WPF forms, just plain Winforms. I would like to populate a TreeView control hierarchically with the parsed data and then make that data responsive to the changes made to the TreeView nodes. I really can't figure out how to bind data to the control itself and allow a mirrored manipulation.
Any suggestion please?
You can populate your TreeView recursively with this code:
protected override void OnLoad( EventArgs e )
{
base.OnLoad( e );
MyValue root = new MyParser().Parse( "MyFilename.own" );
Populate( treeView1.Nodes, root.UnderlyingValue );
}
protected void Populate( TreeNodeCollection nodes, IList list )
{
if( list is MyPair[] )
{
foreach( MyPair pair in list )
{
TreeNode node = new TreeNode();
node.Text = pair.ToString();
node.Tag = pair;
nodes.Add( node );
if( pair.Value.Container )
Populate( node.Nodes, (IList)pair.Value.UnderlyingValue );
}
}
if( list is MyValue[] )
{
foreach( MyValue value in list )
{
TreeNode node = new TreeNode();
node.Text = value.ToString();
node.Tag = value;
nodes.Add( node );
if( value.Container )
Populate( node.Nodes, (IList)value.UnderlyingValue );
}
}
}
Result looks then like that:
As #Reza Aghaei already mentioned it is not possible to do this via data-binding. You have to maintain your lists manually after adding/removing a node. Setting node.Tag to the corresponding pair or value makes it easy for you to find and modify them.

Map a Uri field using Dapper

What is the cleanest way to map a string column to a Uri property using Dapper?
Here's the cleanest I've been able to come up with so far (using the ITypeMap functionality):
Query:
SELECT * FROM TableWithAStringAddressColumn
POCO:
public class MyPoco
{
[ColumnSetter("DapperAddress")]
public Uri Address { get; set; }
private string DapperAddress { set { this.Address = new Uri(value); } }
}
Extensions:
partial class SqlMapper
{
public static void InitializeTypeMaps()
{
SqlMapper.SetTypeMap(
typeof(MyPoco),
new CustomPropertyTypeMap(typeof(MyPoco), SqlMapper.CustomSetterMapper));
// call out every other class that needs this kind of mapping
}
public static Func<Type, string, PropertyInfo> CustomSetterMapper =
(type, columnName) =>
{
PropertyInfo prop = type
.GetProperties()
.FirstOrDefault(p => string.Equals(columnName, p.Name, StringComparison.OrdinalIgnoreCase));
if (prop != null)
{
// find out if we need to use a different setter
ColumnSetterAttribute setterAttribute = prop.GetCustomAttributes(false).OfType<ColumnSetterAttribute>().LastOrDefault();
if (setterAttribute != null)
{
PropertyInfo setterProp = type
.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.FirstOrDefault(p => string.Equals(setterAttribute.Setter, p.Name, StringComparison.OrdinalIgnoreCase));
if (setterProp == null)
{
throw new InvalidOperationException(string.Format("Setter property misconfigured (Property={0}, Setter={1})", prop.Name, setterAttribute.Setter));
}
else
{
prop = setterProp;
}
}
}
return prop;
};
}
Custom Attribute:
public class ColumnSetterAttribute : Attribute
{
public string Setter { get; set; }
public ColumnSetterAttribute(string setter)
{
this.Setter = setter;
}
}
[edit] I'm looking for a solution I can use without needing to call out all columns in all my queries (I'd like to find a solution where I can use SELECT *).
Seems like a lot of work...
Wouldn't this be ok?
public class MyPoco
{
private string _uriMapper;
public Uri SomeUri
{
get { return new Uri(_uriMapper); }
}
public string Mapper { set { _uriMapper = value; } }
}
Edit:
public class UriContainer
{
private string _uriMapper;
public string UriMapper { set { _uriMapper = value; } }
public int Id { get; set; }
public Uri SomeUri { get {return new Uri(_uriMapper);} }
}
public class DbTests
{
[Test]
public void Can_Get_A_Uri()
{
using (var c = new SqlConnection("hello"))
{
c.Open();
var uri = c.Query<UriContainer>("select *, someuri as urimapper from uris where id = 3").Single();
Console.WriteLine(uri.SomeUri);
}
}
}

Unselect ListView-items that are not in the field-of-view

In a ListView, I want the selected items to be always visible (in the current field of view).
Example:
I have six items in my ListView. Only (the top) five are visible.
I select the first item. When I scroll down, this item is not visible anymore, but it remains selected.
I want to DEselect any item that goes out of the current view.
I solved it manually, so it's more a workaround.
I just keep track of the index...
public class ScrollIndexManager
{
private readonly int _viewableItemsCount;
private int _canScrollUpCount;
private int _canScrollDownCount;
public ScrollIndexManager(int viewableItemsCount)
{
_viewableItemsCount = viewableItemsCount;
}
public bool HasChanged { get; set; }
public int BottomVisibleItemIndex
{
get { return TopVisibleItemIndex + _viewableItemsCount - 1; }
}
private int _topVisibleItemIndex = 0;
public int TopVisibleItemIndex
{
get { return _topVisibleItemIndex; }
set
{
if (value < 0)
{
HasChanged = false;
return;
}
_topVisibleItemIndex = value;
HasChanged = true;
}
}
public void SetCanScrollDown(int totalItemCount)
{
_canScrollDownCount = totalItemCount - _viewableItemsCount;
}
public bool CanScrollUp()
{
return _canScrollUpCount > 0;
}
public bool CanScrollDown()
{
return _canScrollDownCount > 0;
}
public bool Increase()
{
TopVisibleItemIndex--;
return HasChanged;
}
public bool Decrease()
{
TopVisibleItemIndex++;
return HasChanged;
}
public void ScrolledUp()
{
_canScrollUpCount--;
_canScrollDownCount++;
}
public void ScrolledDown()
{
_canScrollUpCount++;
_canScrollDownCount--;
}
}

How to best propagate change notifications upwards a hierarchical structure for binding?

If i have a folder-like structure that uses the composite design pattern and i bind the root folder to a TreeView. It would be quite useful if i can display certain properties that are being accumulated from the folder's contents. The question is, how do i best inform the folder that changes occurred in a child-element so that the accumulative properties get updated?
The context in which i need this is a small RSS-FeedReader i am trying to make. This are the most important objects and aspects of my model:
Composite interface:
public interface IFeedComposite : INotifyPropertyChanged
{
string Title { get; set; }
int UnreadFeedItemsCount { get; }
ObservableCollection<FeedItem> FeedItems { get; }
}
FeedComposite (aka Folder)
public class FeedComposite : BindableObject, IFeedComposite
{
private string title = "";
public string Title
{
get { return title; }
set
{
title = value;
NotifyPropertyChanged("Title");
}
}
private ObservableCollection<IFeedComposite> children = new ObservableCollection<IFeedComposite>();
public ObservableCollection<IFeedComposite> Children
{
get { return children; }
set
{
children.Clear();
foreach (IFeedComposite item in value)
{
children.Add(item);
}
NotifyPropertyChanged("Children");
}
}
public FeedComposite() { }
public FeedComposite(string title)
{
Title = title;
}
public ObservableCollection<FeedItem> FeedItems
{
get
{
ObservableCollection<FeedItem> feedItems = new ObservableCollection<FeedItem>();
foreach (IFeedComposite child in Children)
{
foreach (FeedItem item in child.FeedItems)
{
feedItems.Add(item);
}
}
return feedItems;
}
}
public int UnreadFeedItemsCount
{
get
{
return (from i in FeedItems
where i.IsUnread
select i).Count();
}
}
Feed:
public class Feed : BindableObject, IFeedComposite
{
private string url = "";
public string Url
{
get { return url; }
set
{
url = value;
NotifyPropertyChanged("Url");
}
}
...
private ObservableCollection<FeedItem> feedItems = new ObservableCollection<FeedItem>();
public ObservableCollection<FeedItem> FeedItems
{
get { return feedItems; }
set
{
feedItems.Clear();
foreach (FeedItem item in value)
{
AddFeedItem(item);
}
NotifyPropertyChanged("Items");
}
}
public int UnreadFeedItemsCount
{
get
{
return (from i in FeedItems
where i.IsUnread
select i).Count();
}
}
public Feed() { }
public Feed(string url)
{
Url = url;
}
Ok, so here is the thing, if i bind a TextBlock.Text to the UnreadFeedItemsCount there won't be simple notifications when an item is marked unread, so one of my approaches has been to handle the PropertyChanged event of every FeedItem and if the IsUnread-Property is changed i have my Feed make a notification that the property UnreadFeedItemsCount has been changed. With this approach i also need to handle all PropertyChanged events of all Feeds and FeedComposites in Children of FeedComposite, from the sound of it, it should be obvious that this is not such a very good idea, you need to be very careful that items never get added to or removed from any collection without having attached the PropertyChanged event handler first.
Also: What do i do with the CollectionChanged-Events which necessarily also cause a change in the sum of the unread items count? Sounds like more event handling fun.
It is such a mess; it would be great if anyone has an elegant solution to this since i do not want the feed-reader to end up as awful as my first attempt years ago when i did not even know about DataBinding...
Well I thought I'd give your question a go, to see what I would come up with. Its untested and its is kinda along the same lines as what you already had. The major difference I made is added methods to handle the add and removal of feeds which handle the event binding needed for it to work. Theres a bit of code so here goes,
I all my code is in a single file, youll need to modify slightly if you want in in separate files.
First the groovy extension method for the PropertyChangedEventHandler
You dont need to use it, but I like it alot.
public static class NotifyPropertyChangedExtention
{
public static void Raise<T, TP>(this PropertyChangedEventHandler pc, T source, Expression<Func<T, TP>> pe)
{
if (pc != null)
{
pc.Invoke(source, new PropertyChangedEventArgs(((MemberExpression)pe.Body).Member.Name));
}
}
}
Second the FeedItem minus the feed stuff :) I have a check to raise a change event only when the value actually changes. You can see the Raise extension method in use here, no strings lovely.
class FeedItem : INotifyPropertyChanged
{
private bool _isUnread;
public event PropertyChangedEventHandler PropertyChanged;
public bool IsUnread
{
get { return _isUnread; }
set
{
if (_isUnread != value)
{
_isUnread = value;
PropertyChanged.Raise(this, x => x.IsUnread);
}
}
}
}
Now the Interfaces, I made mine differ slightly, in that my folders can contain other folders as well as feeds.
internal interface IFeedComposite : INotifyPropertyChanged
{
string Title { get; set; }
int UnreadFeedItemsCount { get; }
}
internal interface IFeedFolder : IFeedComposite
{
ObservableCollection<IFeedFolder> FeedFolders { get; }
ObservableCollection<IFeed> Feeds { get; }
void AddFeed(IFeed newFeed);
void RemoveFeed(IFeed feedToRemove);
void AddFeedFolder(IFeedFolder newFeedFolder);
void RemoveFeedFolder(IFeedFolder feedFolderToRemove);
}
internal interface IFeed : IFeedComposite
{
ObservableCollection<FeedItem> FeedItems { get; }
void AddFeedItem(FeedItem newFeedItem);
void RemoveFeedItem(FeedItem feedItemToRemove);
}
Now the Feed Class, the AddFeedItem method hooks the property changed event for you, and if it is marked as unread, raises the property changed event for the count. You could overload this method, to accept a list of items, then once they have been added to the list, if any where unread, raise a single property changed event for them all.
class Feed : IFeed
{
private readonly ObservableCollection<FeedItem> _feedItems = new ObservableCollection<FeedItem>();
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
public int UnreadFeedItemsCount
{
get
{
return (from i in FeedItems
where i.IsUnread
select i).Count();
}
}
public ObservableCollection<FeedItem> FeedItems
{
get { return _feedItems; }
}
public void AddFeedItem(FeedItem newFeed)
{
newFeed.PropertyChanged += NewFeedPropertyChanged;
_feedItems.Add(newFeed);
PropertyChanged.Raise(this, x => x.FeedItems);
if (newFeed.IsUnread)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
public void RemoveFeedItem(FeedItem feedToRemove)
{
_feedItems.Remove(feedToRemove);
PropertyChanged.Raise(this, x => x.FeedItems);
if (feedToRemove.IsUnread)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
void NewFeedPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "IsUnread")
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
}
Now the FeedFolder class, much the same as the feed class but this one can hold a list of feeds and a list of feed folders (which hold their own feeds). You can easily add a method or property to return all feeditems from feeds and feedfolders if you need. Again, various checks to only raise change events if needed.
class FeedFolder : IFeedFolder
{
private readonly ObservableCollection<IFeedFolder> _feedFolders = new ObservableCollection<IFeedFolder>();
private readonly ObservableCollection<IFeed> _feeds = new ObservableCollection<IFeed>();
public event PropertyChangedEventHandler PropertyChanged;
public string Title { get; set; }
public int UnreadFeedItemsCount
{
get { return Feeds.Sum(x => x.UnreadFeedItemsCount) + FeedFolders.Sum(x => x.UnreadFeedItemsCount); }
}
public ObservableCollection<IFeedFolder> FeedFolders
{
get { return _feedFolders; }
}
public ObservableCollection<IFeed> Feeds
{
get { return _feeds; }
}
public void AddFeed(IFeed newFeed)
{
newFeed.PropertyChanged += NewFeedPropertyChanged;
_feeds.Add(newFeed);
PropertyChanged.Raise(this, x => x.Feeds);
if (newFeed.UnreadFeedItemsCount > 0)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
void NewFeedPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "UnreadFeedItemsCount")
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
public void RemoveFeed(IFeed feedToRemove)
{
_feeds.Remove(feedToRemove);
PropertyChanged.Raise(this, x => x.Feeds);
if (feedToRemove.UnreadFeedItemsCount > 0)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
public void AddFeedFolder(IFeedFolder newFeedFolder)
{
newFeedFolder.PropertyChanged += NewFeedPropertyChanged;
_feedFolders.Add(newFeedFolder);
PropertyChanged.Raise(this, x => x.FeedFolders);
if (newFeedFolder.UnreadFeedItemsCount > 0)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
public void RemoveFeedFolder(IFeedFolder feedFolderToRemove)
{
_feedFolders.Remove(feedFolderToRemove);
PropertyChanged.Raise(this, x => x.FeedFolders);
if (feedFolderToRemove.UnreadFeedItemsCount > 0)
{
PropertyChanged.Raise(this, x => x.UnreadFeedItemsCount);
}
}
}
Now for usage, remember I havent tested this, but it should be mostly right.
var myFolder = new FeedFolder();
var myFeed = new Feed();
var myFeedItem = new FeedItem();
myFeedItem.IsUnread = true;
myFeed.AddFeedItem(myFeedItem);
myFolder.AddFeed(myFeed);
var mySecondFeedItem = new FeedItem();
//add a second feeditem to feed, but it is marked as read, so no notifications raised for unread count.
myFeed.AddFeedItem(mySecondFeedItem);
//this should fire off change events all the way up to the folder
mySecondFeedItem.IsUnread = true;

property names are different from original Object in the silverlight

Following is part of service layer which is provided by WCF service :
[Serializable]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
public class Service1 : IService1
{
public List<WaitInfo> GetWaitingList()
{
MyDBDataContext db = new MyDBDataContext();
var query = from w in db.WAIT_INFOs
select new WaitInfo
{
TagNo = w.PATIENT_INFO.TAG_NO,
RoomName= w.ROOM_INFO.ROOM_NAME,
PName= w.PATIENT_INFO.P_NAME
};
List<WaitInfo> result = query.ToList();
return result;
}
And following is codebehind part of UI layer which is provided by Silverlight
public MainPage()
{
InitializeComponent();
Service1Client s = new Service1Client();
s.GetWaitingListCompleted +=
new EventHandler<GetWaitingListByCompletedEventArgs>( s_GetWaitingListCompleted);
s.GetWaitingListAsync();
}
void s_GetWaitingListCompleted(object sender,
RadControlsSilverlightApplication1.ServiceReference2.GetWaitingListByCompletedEventArgs e)
{
GridDataGrid.ItemsSource = e.Result;
}
And following is xaml code in Silverlight page
<Grid x:Name="LayoutRoot">
<data:DataGrid x:Name="GridDataGrid"></data:DataGrid>
</Grid>
It is very simple code, however what I am thinking weird is property name of object at "e.Result" in the code behind page.
In the service layer, although properties' names are surely "RoomName, PName, TagNo", in the silverlight properties' names are "roomName, pName, tagNo" which are private variable name of the WaitingList Object.
Did I something wrong?
Thanks in advance.
Unless you specifically decorate your class with the DataContract attribute (which you should, instead of Serializable) then a default DataContract will be inferred. For normal Serializable types, this means the fields will be serialized as opposed to the properties.
You can markup your class in either of the following two ways. The latter will use the property accessors when serializing/deserializing your object which may be very useful or be a hassle depending on your circumstances.
[DataContract]
public class WaitInfo
{
[DataMember(Name="RoomName")]
private string roomName;
[DataMember(Name="PName")]
private string pName;
[DataMember(Name="TagNo")]
private string tagNo;
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
public string PName
{ get { return pName; } set { this.pName = value; } }
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}
The method I prefer:
[DataContract]
public class WaitInfo
{
private string roomName;
private string pName;
private string tagNo;
[DataMember]
public string RoomName
{ get { return roomName; } set { this.roomName = value; } }
[DataMember]
public string PName
{ get { return pName; } set { this.pName = value; } }
[DataMember]
public string TagNo
{ get { return tagNo; } set { this.tagNo = value; } }
}

Resources