I have multiple dictionaries. Each of them contains the same keys, just with different values. I am using them for translations. They are dynamically created..
So, it looks something like this:
DictionaryEng:
first_page_name = "First page"
second_page_name = "Second page"
DictionaryRu:
first_page_name = "Первая страница"
second_page_name = "Вторая страница"
I would like this informations to be shown in DataGrid or, so user can change the values. It should look like this, end values to be editable.
What's the best practice to do this?
Basically you need to bind the DataGrid to a Collection
<DataGrid
ItemsSource="{Binding Lines}" AutoGenerateColumns="True"
I'll mock up the creation of the dictionary with stub functions called in the ViewModel c.tor
public class MyVM : ViewModelBase
{
public MyVM()
{
Line.DictionaryEng = Line.DictionaryEngStub();
Line.DictionaryRu = Line.DictionaryRuStub();
lines = new ObservableCollection<Line>(Line.DictionaryEng.Keys.Select(k => new Line() { KeyWord = k }));
}
private ObservableCollection<Line> lines;
public ObservableCollection<Line> Lines
{
get { return lines; }
set
{
lines = value;
OnPropertyChanged("Lines");
}
}
}
where the underlying class is defined as follows
public class Line : ViewModelBase
{
internal static Dictionary<string, string> DictionaryEngStub()
{
return new Dictionary<string, string>()
{
{ "first_page_name ","First page" },
{ "second_page_name ","Second page" }
};
}
internal static Dictionary<string, string> DictionaryRuStub()
{
return new Dictionary<string, string>()
{
{"first_page_name ","Первая страница" },
{"second_page_name ","Вторая страница" }
};
}
internal static Dictionary<string, string> DictionaryEng = new Dictionary<string, string>();
internal static Dictionary<string, string> DictionaryRu = new Dictionary<string, string>();
private string keyWord;
public string KeyWord
{
get { return keyWord; }
set
{
keyWord = value;
OnPropertyChanged("keyWord");
}
}
public string EnglishWord {
get
{
string english;
if (DictionaryEng.TryGetValue(keyWord ?? "", out english))
{
return english;
}
return null;
}
}
public string RussianhWord
{
get
{
string russian;
if (DictionaryRu.TryGetValue(keyWord ?? "", out russian))
{
return russian;
}
return null;
}
}
}
Notice that the translations have only a getter to retrieve the string from the dictionary.
You can easily make them editable by adding a setter to save the new translation into a persistence layer. Furthermore, English and Russian dictionaries are generic enough to be renamed as from/to dictionaries. Once the user selects a language in another combobox, you can reset the dictionary accordingly.
Since I have a stub here, the setter does not make much sense, but just to give you and idea...
private string englishSaved;
public string EnglishWord {
get
{
if (englishSaved != null)
{
return englishSaved;
}
string english;
if (DictionaryEng.TryGetValue(keyWord ?? "", out english))
{
return english;
}
return null;
}
set
{
englishSaved = value; //save the new translation into a persistence layer
}
}
Related
I'm trying to implement a class with a property which can be accessed only with parameter. To clear my question see how I intend to use it
Note that this is different than Indexer. Please don't flag for duplicate.
My incomplete class
public class Inventory{
public object Options..... // I don't know how to define this property
}
How I'm going to use it
Inventory inv = new Inventory();
string invLabel = (string)inv.Options["Label"];
int size = inv.Options["Size"];
inv.Options["Weight"] = 24;
Internally, Options reads data from a private Dictionary. Please help me on how I can define the Options property.
Note: This is different than Indexer. With Indexer, I can use below code:
int size = inv["Size"];
But my usage is different.
I found a way to implement it.
public class Options
{
public Dictionary<string, object> _options;
public Options()
{
_options = new Dictionary<string, object>();
}
public object this[string key] {
get { return _options.Single(r => r.Key == key).Value; }
set { _options[key] = value; }
}
}
public class Inventory
{
public Inventory()
{
Options = new Options();
}
public Options Options { get; set; }
}
Usage:
var x = new Inventory();
x.Options["Size"] = 120;
x.Options["Box"] = "4 x 4 x 8";
Console.WriteLine(x.Options["Size"]);
Console.WriteLine(x.Options["Box"]);
I want to create "list of list of list". It should be:
Group (has a list of Members)
Member (has a Name and list of Properties)
Property (has Name and Value)
What I want is to have a possibility to add Property into Member (specified by its name) inside defined Group. Someting like this:
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
I have trouble achieving this using list... I found class Hashable, but I am not sure if this is usable... and cannot make it works too...
Thank for any suggestion :)
Well, I suggest you create a custom class instead of your approach. But otherwise you can use a Dictionary.
var properties = new Dictionary<string, string>();
properties.Add("Prop1", "Value");
var members = new Dictionary<string, Dictionary<string, string>>();
members.Add("Member1", properties);
var group = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
group.Add("GroupName", members);
public class Group
{
public Group()
{
Members = new List<Member>();
}
public IEnumerable<Member> Members { get; set; }
}
public class Member
{
public Member()
{
Properties = new Dictionary<string, string>();
}
public string Name { get; set; }
IDictionary<string, string> Properties { get; set; }
}
The dictionary can take a key and a value, and the key should be unique.
You can also create a class property if you want to add another thing beside the name and the value
I would use indexers.
Here's a partial implementation:
class Group
{
private List<Member> _members;
public string this
{
get
{
return _members.Find(m => m.Name == value);
}
// You can also implement set here if you want...
}
}
class Member
{
private List<Property> _properties;
public string Name {get;set;}
public string this
{
get
{
return _properties.Find(m => m.Name == value);
}
}
}
class Property
{
public string Name {get;set;}
public string Value {get;set;}
}
And the usage:
var g = new Group();
g[memberName][propertyName].Value = someValue;
Note: This implementation is partial! it still needs constructor logic and any other logic you might need.
Likely the best solution is to use the C# class Dictionary - as suggested by zetawars, or a custom class - as suggested by Zohar Peled, or some mix of the two - as suggested by gandalf.
However, in order to use syntax similar to what is requested in the question...
membersgroup.AddNewMember(memberXYZ);
...
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ).
You can abuse ExpandoObject and Action, and do something awesome like this:
dynamic membersgroup = new ExpandoObject();
var getNewMemberObject = new Func<dynamic>(() =>
{
dynamic memberObject = new ExpandoObject();
var addPropertyAction = new Action<string, string>((propertyName, propertyValue) =>
{
((IDictionary<string, object>)memberObject).Add(propertyName, propertyValue);
});
memberObject.AddProperty = addPropertyAction;
return memberObject;
});
var addNewMemberAction = new Action<string>((memberName) =>
{
((IDictionary<string, object>)membersgroup).Add(memberName, getNewMemberObject());
});
membersgroup.AddNewMember = addNewMemberAction;
string memberXYZ = nameof(memberXYZ);
string nameXYZ = nameof(nameXYZ);
string valueXYZ = nameof(valueXYZ);
// look we did it!
membersgroup.AddNewMember(memberXYZ);
membersgroup.memberXYZ.AddProperty(nameXYZ, valueXYZ);
// and it actually works
var actualValue = membersgroup.memberXYZ.nameXYZ;
Console.WriteLine(actualValue); // "valueXYZ"
(for science of course)
I was originally experiencing a problem in my code in which I was unable to "add" an item to a list object. After reviewing the list object however, I realized it only contained a "get", not a "set". So, I'm trying to create a set accessor but I'm having issues:
Here's my original code to add an item to the list object. Currently, nothing gets added:
ClientCompany clientCompany = new ClientCompany();
LocationData urlData = new LocationData();
Location location = urlData.LocationGet(1129); //hardcoded 1129 in for now
clientCompany.Locations.Add(location); //"location" is NOT null, however nothing gets added to Locations object
return clientCompany; //clientCompany.Locations.Count = 0 (it should equal 1)
And here's the current portion of the ClientCompany class I'm having trouble with:
public Dictionary<int, Location> LocationsDict { get; set; }
// List Properties
public List<Location> Locations
{
get { return LocationsDict.Values.ToList(); }
}
I tried including a setter, but I receive the following error:
Cannot convert source type
Systems.Collections.Generic.List<MyCompany.MVC.MyProject.Models.ClientCompany.Location>'
to target type 'Systems.Collections.Generic.Dictionary<int,
MyCompany.MVC.MyProject.Models.ClientCompany.Location>
get { return LocationsDict.Values.ToList(); }
set { LocationsDict = value; }
Any idea what I'm doing wrong?
Thanks
i 'll do something like this:
private Dictionary<int, Location> LocationsDict = new Dictionary<int, Location>();
public void Set(int key, Location value)
{
if (LocationsDict.ContainsKey(key))
LocationsDict[key] = value;
else
LocationsDict.Add(key, value);
}
public Location Get(int key)
{
return LocationsDict.ContainsKey(key) ? LocationsDict[key] : null; }
}
or better (i think) you could use indexer:
public class MyClass
{
private readonly IDictionary<int, Location> LocationsDict = new Dictionary<int, Location>();
public Location this[int key]
{
get { return LocationsDict.ContainsKey(key) ? LocationsDict[key] : null; }
set
{
if (LocationsDict.ContainsKey(key))
LocationsDict[key] = value;
else
LocationsDict.Add(key, value);
}
}
}
var gotest = new MyClass();
gotest[0] = new Location(){....};
I have a (string, object) dictionary, object (class) has some values including data type which is defined by enum. I need a GetItemValue method that should return dictionary item's value. So return type must be the type which is defined in item object.
Class Item
{
String Name;
DataValueType DataType;
Object DataValue;
}
private Dictionary<string, Item> ItemList = new Dictionary<string, Item>();
void Main()
{
int value;
ItemList.Add("IntItem", new Item("IntItem", DataValueType.TInt, 123));
value = GetItemValue("IntItem"); // value = 123
}
What kind of solution can overcome this problem?
Best Regards,
You can use Generic Classes
Class Item<T>
{
String Name;
T DataTypeObject;
Object DataValue;
public T GetItemValue()
{
//Your code
return DataTypeObject;
}
}
A better solution would be to introduce an interface that you make all the classes implement. Note that the interface doesn't necessarily have to specify any behavior:
public interface ICanBePutInTheSpecialDictionary {
}
public class ItemTypeA : ICanBePutInTheSpecialDictionary {
// code for the first type
}
public class ItemTypeB : ICanBePutInTheSpecialDictionary {
// code for the second type
}
// etc for all the types you want to put in the dictionary
To put stuff in the dictionary:
var dict = new Dictionary<string, ICanBePutInTheSpecialDictionary>();
dict.add("typeA", new ItemTypeA());
dict.add("typeB", new ItemTypeB());
When you need to cast the objects to their specific types, you can either use an if-elseif-block, something like
var obj = dict["typeA"];
if (obj is ItemTypeA) {
var a = obj as ItemTypeA;
// Do stuff with an ItemTypeA.
// You probably want to call a separate method for this.
} elseif (obj is ItemTypeB) {
// do stuff with an ItemTypeB
}
or use reflection. Depending on how many choices you have, either might be preferrable.
If you have a 'mixed bag' you could do something like this...
class Item<T>
{
public String Name { get; set; }
public DataValueType DataType { get; set; }
public T DataValue { get; set; }
}
class ItemRepository
{
private Dictionary<string, object> ItemList = new Dictionary<string, object>();
public void Add<T>(Item<T> item) { ItemList[item.Name] = item; }
public T GetItemValue<T>(string key)
{
var item = ItemList[key] as Item<T>;
return item != null ? item.DataValue : default(T);
}
}
and use it like...
var repository = new ItemRepository();
int value;
repository.Add(new Item<int> { Name = "IntItem", DataType = DataValueType.TInt, DataValue = 123 });
value = repository.GetItemValue<int>("IntItem");
If you have just a couple types - you're better off with Repository<T>.
I found a solution exactly what I want. Thanks to uncle Google.
Thanks all of you for your kind interest.
public dynamic GetValue(string name)
{
if (OpcDataList[name].IsChanged)
{
OpcReflectItem tmpItem = OpcDataList[name];
tmpItem.IsChanged = false;
OpcDataList[name] = tmpItem;
}
return Convert.ChangeType(OpcDataList[name].ItemValue.Value, OpcDataList[name].DataType);
}
I have a situation that is pretty simple, and I'd like to know the ideal way to do it.
I have a combo box. Each line of the combo box corresponds to a particular strategy object.
What is the proper way to map the combo box lines to the strategy object.
The way I was doing it seems overly complicated, and I'm pretty much guaranteed there is a simple standard way to do this.
Thank you.
EDIT:
I had the data in a Dictionary, where the string was the text for the combobox, and the object was the strategy... But this isn't ordered... And I just know there is some extremely simple way to do it.
SOLUTION:
I used this solution, not feeling comfortable putting presentation logic in the data classes:
private partial class HtmlTransformState : AbstractHtmlEditFormState
{
private Dictionary<string, ITransformStrategy> strategies = new Dictionary<string, ITransformStrategy>()
{
{ "Simple URL", new TransformStrategy<SimpleUrlCodeExtractor>() },
{ "Overview", new TransformStrategy<OverviewCodeExtractor>() },
{ "Video List", new TransformStrategy<VideoListCodeExtractor>() },
{ "Video List No MbORKb", new TransformStrategy<VideoListNoMBOrKBAndNoLinksAllowedCodeExtractor>() },
{ "Blue Mountain 2007", new TransformStrategy<BlueMountain2007CodeExtractor>() },
{ "Four Gates", new TransformStrategy<FourGatesCodeExtractor>() },
{ "General", new TransformStrategy<GeneralCodeExtractor>() }
};
public override void DrawForm()
{
// ...
ParentForm.cmboTransformStrategy.DataSource = new BindingSource(strategies, null);
ParentForm.cmboTransformStrategy.DisplayMember = "Key";
ParentForm.cmboTransformStrategy.ValueMember = "Value";
}
public override IEnumerable<string> ProcessHtml(string urlPath)
{
ITransformStrategy transformStrategy = (ITransformStrategy)ParentForm.cmboTransformStrategy.SelectedValue;
// Do some stuff with 'transformStrategy'
}
}
Do you mean something like the following?
public class Strategy
{
private string _name = "default";
public string Name
{
get { return _name; }
set { _name = value; }
}
public Strategy(string name)
{
_name = name;
}
}
Then in form load (you need to have a combo box on that form):
private void Form1_Load(object sender, EventArgs e)
{
List<Strategy> ls = new List<Strategy>();
ls.Add(new Strategy("First"));
ls.Add(new Strategy("Second"));
ls.Add(new Strategy("Third"));
comboBox1.DataSource = ls;
comboBox1.DisplayMember = "Name";
}
Override ToString for your strategy object. After that you can insert your strategy objects directly in the combo box.
public class StrategyObject
{
public override string ToString()
{
return "return the text to display";
}
}
StrategyObject selectedStratObj = comboBox1.SelectedItem as StrategyObject;
I would use the SelectedIndexChanged event on the combobox and select the corresponding dictionary entry
found that, Bind a Dictionary to a ComboBox see below for a working example(at least on the original vb.net code that I wrote)
Vb.net converted into C#, you will have to manage the handle yourself
public class Form1
{
private Dictionary<int, myDic> dict = new Dictionary<int, myDic>();
private void // ERROR: Handles clauses are not supported in C#
ComboBox1_SelectedIndexChanged(System.Object sender, System.EventArgs e)
{
KeyValuePair<int, myDic> curItem = (KeyValuePair<int, myDic>)ComboBox1.SelectedItem;
MessageBox.Show(curItem.Value.myvalue);
}
private void // ERROR: Handles clauses are not supported in C#
Form1_Load(object sender, System.EventArgs e)
{
myDic d = default(myDic);
for (int i = 0; i <= 10; i++) {
d = new myDic();
d.myKey = i.ToString;
d.myvalue = Strings.Chr(65 + i);
dict.Add(d.GetHashCode, d);
}
ComboBox1.DataSource = new BindingSource(dict, null);
ComboBox1.DisplayMember = "value";
ComboBox1.ValueMember = "Key";
}
}
class myDic
{
public string myKey;
public string myvalue;
public override string tostring()
{
return myvalue;
}
}
Here's one of my finest innovations. :) I'm really proud of this little one.
public class Stringable<T>
{
private T _obj;
private Func<T, string> _convertFn;
public Stringable(T obj, Func<T, string> convertFn)
{
_obj = obj;
_convertFn = convertFn;
}
public T GetObj() { return _obj; }
public override string ToString() { return _convertFn(_obj); }
}
This generic class adds ToString() to any class (even a black-box class) and you can define its behavior inside the lambda. Imagine you have a class Person with properties FirstName and LastName. Here's how you would use it to populate Combo box.
_cboPersons.Items.Add(new Stringable<Person>(person,o=>string.Format("{0}, {1}", o.LastName, o.FirstName)));
Then, when combo box item is selected just use this to get the original object from your combo
Person person=(_cboPersons.SelectedItem as Stringable<Person>).GetObj() // Get's person object.