I have a class
public class TextBoxConfig
{
public string Caption { get; set; }
public string FieldName { get; set; }
public int Width { get; set; }
public string Name { get; set; }
}
and one other utility class that has a Method that accepts TextBoxConfig as a parameter like this
public class Util
{
public static TextBox ApplySettings(TextBoxConfig config)
{
//Doing something
}
}
In general I can call Util class ApplySettings method like this
TextBoxConfig config = new TextBoxConfig();
config.Caption = "Name";
config.FieldName = "UserName"
config.Width = 20;
config.Name = "txtName";
TextBox txt = Util.ApplySettings(config);
but I want to pass parameter to ApplySettings like this
TextBox txt = Util.ApplySettings(o =>
{
o.Caption = "Name";
o.FieldName = "UserName"
o.Width = 20;
o.Name = "txtName";
});
Please suggest me how can I do it ..
Okay, brace yourself: here is the same thing, just enforced with lambda expressions.
TextBox txt = Util.ApplySettings(o =>
{
o.Caption = "Name";
o.FieldName = "UserName";
o.Width = 20;
o.Name = "txtName";
});
public class Util
{
public static TextBox ApplySettings(TextBoxConfig config)
{
//Doing something
}
public static TextBox ApplySettings(Action<TextBoxConfig> modifier)
{
var config = new TextBoxConfig();
modifier(config);
return ApplySettings(config);
}
}
I had to add some semicolons after the statements. And I'd prefer the other answer. But I hope this fulfills your desire for lambda expressions.
Not exactly the same as your wish, but pretty close:
TextBox txt = Util.ApplySettings(new TextBoxConfig()
{
Caption = "Name",
FieldName = "UserName",
Width = 20,
Name = "txtName"
});
Note the commas after each setting. See http://msdn.microsoft.com/en-us/library/vstudio/bb397680.aspx.
Related
I am using dotConnect for MySQL product of Devart. MySQL database structure likes this:
I am getting data like this:
public int user_id { get; set; } = 2;
public string lang { get; set; } = "en"; // Depending on the situation, it may also be "tr".
private readonly mainDataContext _db = new();
var cats = _db.categories.Where(s => s.u_id == user_id);
foreach (var cat in cats)
{
MessageBox.Show(cat.name_en);
}
In the MessageBox.Show I can not use cat.name + "_" + lang like PHP. I don't know how to get over this problem.
In nutshell, you can use this:
cat.GetType().GetProperty("name_" + lang).GetValue(cat,null))
But it's better to call a method to get value:
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
Here is a full example:
using System;
namespace Example
{
public class user
{
public int user_id { get; set; } = 2;
public string name_en { get; set; }
public string name_tr { get; set; }
}
class Program
{
static public T getval<T>(Object obj, string field)
{
return (T)obj.GetType().GetProperty(field).GetValue(obj, null);
}
static void Main(string[] args)
{
List<user> u = new List<user>();
u.Add(new user { user_id = 1, name_en = "Foods", name_tr = "name_tr value 1" });
u.Add(new user { user_id = 2, name_en = "Pizza", name_tr = "name_tr value 2" });
u.Add(new user { user_id = 2, name_en = "Other", name_tr = "name_tr vale 3" });
var lang = "en";
var cats = u.Where(s => s.user_id == 2);
foreach (var cat in cats)
{
Console.WriteLine(getval<string>(cat,"name_"+lang));
}
return;
}
}
}
I'm trying to create a .dat file with a pipe (|) separator.
I'm not sure how I can set custom column names I can use in a .dat file.
I have a class that would look like this :
public partial class ExportData
{
[DatColumnName="Test Code 123"]
public string Code { get; set; }
[DatColumnName="Test Name 123"]
public string Name { get; set; }
[DatColumnName="Test Address_123"]
public string Address { get; set; }
}
As a result, I would like to get something like this in the file:
Test Code 123|Test Name 123|Test Address_123
1|Name1|Address1
etc.
I guess below code will works for you.
I could handle it without custom attribute.
Code
public static class Extensions
{
public static string Piped<T>(this IList<T> source)
{
var sb = new StringBuilder();
var pInfo = typeof(T).GetProperties().Where(x => x.GetCustomAttributes<DisplayNameAttribute>().Any());
bool first = true;
foreach (var i in source)
{
if (first)
{
//foreach (var h in pInfo.Select(x => x.GetCustomAttribute<DisplayNameAttribute>().DisplayName))
//{
// sb.Append(h);
// sb.Append('|');
//}
sb.Append(string.Join('|', pInfo.Select(x => x.GetCustomAttribute<DisplayNameAttribute>().DisplayName)));
sb.Append(Environment.NewLine);
first = false;
}
foreach (var y in i.GetType().GetProperties().Where(x => x.GetCustomAttributes<DisplayNameAttribute>().Any()))
{
sb.Append(i.GetType().GetProperty(y.Name).GetValue(i, null).ToString());
sb.Append('|');
}
sb.Append(Environment.NewLine);
}
return sb.ToString();
}
}
Usage
public partial class ExportData
{
[DisplayName("Test Code 123")]
public string Code { get; set; }
[DisplayName("Test Name 123")]
public string Name { get; set; }
[DisplayName("whatever you want")]
public string Address { get; set; }
}
static void Main(string[] args)
{
var lst = new List<ExportData>() {
new ExportData{ Code = "c1", Name ="n1", Address = "a1" },
new ExportData{ Code = "c2", Name ="n2", Address = "a2" },
new ExportData{ Code = "c3", Name ="n3", Address = "a3" },
};
Console.WriteLine(lst.Piped());
Console.ReadKey();
}
Result
Test Code 123|Test Name 123|Whatever you want|
c1|n1|a1|
c2|n2|a2|
c3|n3|a3|
I have a generic class, JSTable, that takes a type RowType. I want to have a class that can contain many JSTables, each with a different RowType, so that I may do something like the Func<> in C# does, where it has many optional types. Is this only possible because there are many representations of Func<>? I want a limitless option, so that I could potentially declare a JSGridVM with hundreds of tables, or one table.
public class JSGridVM<?>//where ? is as many types as I want
{
public List<JSTable<?>> Tables { get; set; };
}
public class JSTable<RowType>
{
public JSTable() { }
public JSTable(List<RowType> rows, List<JSGridColumn> columns, bool allowEditingRows, bool allowDeletingRows, string updateURL, string deleteURL)
{
Rows = rows;
Columns = columns;
AllowEditingRows = allowEditingRows;
AllowDeletingRows = allowDeletingRows;
UpdateURL = updateURL;
DeleteURL = deleteURL;
}
public List<RowType> Rows { get; set; }
public List<JSGridColumn> Columns { get; set; }
public bool AllowEditingRows { get; set; }
public bool AllowDeletingRows { get; set; }
public string UpdateURL { get; set; }
public string DeleteURL { get; set; }
}
public class JSGridColumn
{
public string PropertyName { get; set; }
public ColumnType Type { get; set; }
}
public enum ColumnType
{
Text,
Hidden,
}
Then declare like
var jsGridVM = new JSGridVM<SomeClass1, SomeClass2, SomeClass3>();
OR
var jsGridVM = new JSGridVM<SomeClass1>();
You should declare generic type argument <RowType> not at class level, but at methods: AddTable and GetTable:
public class JSGridVM
{
private Dictionary<Type, object> Tables = new Dictionary<Type, object>();
public JSGridVM AddJSTable<RowType>()
{
Tables.Add(typeof(RowType), new JSTable<RowType>());
return this;
}
public JSTable<RowType> GetJSTable<RowType>()
{
Tables.TryGetValue(typeof(RowType), out object temp);
return (JSTable<RowType>)temp;
}
}
Usage:
var sample = new JSGridVM();
sample.AddJSTable<RowTypeA>().AddJSTable<RowTypeB>();
var test = a.GetJSTable<RowTypeA>();
You could roll your own class, but the .NET DataSet class might be what you are after. DataSet has been around for ages and is still pretty useful.
var ds = new DataSet();
var dataTable = new DataTable("DataTable");
var stringCol = new DataColumn("String Column", typeof(string));
var intCol = new DataColumn("Integer Column", typeof(int));
var decimalCol = new DataColumn("Decimal Column", typeof(decimal));
dataTable.Columns.AddRange(new [] {stringCol, intCol, decimalCol});
var newRow = new object[]
{
"String item",
1,
100.08m
};
dataTable.Rows.Add(newRow);
ds.Tables.Add(dataTable);
var row = ds.Tables["DataTable"].Rows[0];
var stringRowValue = row["String Column"];
var intRowValue = row["Integer Column"];
var decimalRowValue = row["Decimal Column"];
Console.WriteLine($"String value: {stringRowValue}\nInteger value: {intRowValue}\nDecimal Value: {decimalRowValue}");
var rowArr = new DataRow[ds.Tables["DataTable"].Rows.Count];
ds.Tables["DataTable"].Rows.CopyTo(rowArr, 0);
var list = rowArr.ToList();
foreach (DataRow rowitem in list)
{
Console.WriteLine($"\nFrom List: String value: {rowitem["String Column"]}\nInteger value: {rowitem["String Column"]}\nDecimal Value: {rowitem["String Column"]}");
}
Console.ReadKey();
Not sure what you are trying to accomplish, but this is already pretty robust. If you are trying to accomplish a specific use case by creating a generic class, then check out MSDN for more help.
Using Generics:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-type-parameters
Func:
https://msdn.microsoft.com/en-us/library/bb549151(v=vs.110).aspx
Why not :
public class JSGridVM<JSTable>
{
public List<JSTable> Tables { get; set; };
}
public class JSTable<?>
{
}
var rowTypeAnimals = AnimalRowType();
var rowTypeBirds = BirdRowType();
var animalTable = new JSTable<AnimalRowType>(){rowTypeAnimals };
var birdTable = new JSTable<BirdRowType>(){rowTypeBirds };
var grid = new JSGridVM(){animalTable,birdTable};
Keep the row type generic for your table and your grid will always have the same JSTable type.
I have an interesting question, one I'm having difficulty searching for an answer on.
I have two IEnumerable collections of objects. The underlying objects are completely separate, BUT I can identify a shared key that should match. The collections are important, in that my "left" object is the "system of record", and the "right" object is representing a system I need to ensure matches the system of record.
Once they are matched, I need to perform CRUD operations on one side to bring the right side in line with the left side. For example, it would create a new item on the right side if one didn't exist, or update values, or delete if the item was missing on the left, but not the right.
The catch is, I have hundreds of these collections to match up, and the actual CRUD code is different.
I'd like to introduce some shared code where I can pass in both collections, the collection types (as probably generics), some kind of comparer, and some delegates of what operation to perform for CRUD.
If this code actually existed, it may look something like this
class Stuff
{
string Id {get; set;}
string Name {get; set;}
}
class Junk
{
string Id {get; set;}
string ShortName {get; set;}
}
IEnumerable<Stuff> myStuff = GetStuff();
IEnumerable<Junk> myJunk = GetJunk();
CrudComparer cc = new CrudComparer<Stuff, Junk>(myStuff, myJunk);
cc.Comparer = (leftObject, rightObject) => {
leftObject.Name == rightObject.Name
}
cc.CreateOperation = (newObject, rightCollection) => {
Junk j = new Junk();
j.Shortname = newObject.Name;
rightCollection.Add(j);
}
cc.UpdateOperation = (leftObject, rightObject) => {
rightObject.Shortname = leftObject.Name;
}
cc.DeleteOperation = (rightCollection, rightObject) => {
rightCollection.Remove(rightObject);
}
cc.Compare();
Has anyone ever seen code that does something like this? I'd hate to reinvent the wheel if I can grab something already done.
Thanks for any help!
--Michael
I got to thinking more about this, and realized what I knew about delgates and generics should be sufficient to solve this problem, so I got in LinqPad and had some fun. I haven't written any unit tests around this yet, so use at your own risk, but hopefully if you want to use this you understand the underlying concepts.
class Blah
{
public int ID { get; set; }
public string BlahName { get; set;}
}
class Bleh
{
public int ID { get; set; }
public string BlehName { get; set;}
}
class CrudComparer<TLeft, TRight>
{
private readonly ICollection<TLeft> _leftCollection;
private readonly ICollection<TRight> _rightCollection;
private readonly Comparer _compareOperation;
private readonly CreateOperation _createOperation;
private readonly UpdateOperation _updateOperation;
private readonly DeleteOperation _deleteOperation;
public delegate bool Comparer(TLeft leftItem, TRight rightItem);
public delegate void CreateOperation(TLeft leftItem, ICollection<TRight> rightCollection);
public delegate void UpdateOperation(TLeft leftItem, TRight rightItem);
public delegate void DeleteOperation(TRight rightItem, ICollection<TRight> rightCollection);
public CrudComparer(ICollection<TLeft> leftCollection, ICollection<TRight> rightCollection, Comparer compareOperation, CreateOperation createOperation, UpdateOperation updateOperation, DeleteOperation deleteOperation)
{
_leftCollection = leftCollection;
_rightCollection = rightCollection;
_compareOperation = compareOperation;
_createOperation = createOperation;
_updateOperation = updateOperation;
_deleteOperation = deleteOperation;
}
public void Compare()
{
foreach (TLeft leftItem in _leftCollection)
{
bool foundItem = false;
foreach (TRight rightItem in _rightCollection)
{
if (_compareOperation(leftItem, rightItem))
{
//these equal
foundItem = true;
}
}
if (foundItem == false)
{
_createOperation(leftItem, _rightCollection);
}
}
List<TRight> itemsToDelete = new List<TRight>();
foreach (TRight rightItem in _rightCollection)
{
bool foundItem = false;
foreach (TLeft leftItem in _leftCollection)
{
if (_compareOperation(leftItem, rightItem))
{
foundItem = true;
_updateOperation(leftItem, rightItem);
break;
}
}
if (!foundItem)
{
itemsToDelete.Add(rightItem);
}
}
foreach (TRight itemToDelete in itemsToDelete)
{
_deleteOperation(itemToDelete, _rightCollection);
}
}
}
void Main()
{
List<Blah> blahItems = new List<Blah>();
blahItems.Add(new Blah() { ID = 1, BlahName = "Blah" });
blahItems.Add(new Blah() { ID = 2, BlahName = "ABC" });
blahItems.Add(new Blah() { ID = 34, BlahName = "XYZ" });
blahItems.Add(new Blah() { ID = 6442, BlahName = "123" });
List<Bleh> blehItems = new List<Bleh>();
blehItems.Add(new Bleh() { ID = 2, BlehName = "12345"});
blehItems.Add(new Bleh() { ID = 6, BlehName = "43232"});
blehItems.Add(new Bleh() { ID = 77, BlehName = "BlahBlah"});
blehItems.Add(new Bleh() { ID = 2334, BlehName = "ZYX"});
CrudComparer<Blah, Bleh>.Comparer compareOperation = (leftObject, rightObject) =>
{
return leftObject.ID == rightObject.ID;
};
CrudComparer<Blah, Bleh>.CreateOperation createOperation = (leftObject, rightCollection) =>
{
rightCollection.Add(new Bleh() { ID = leftObject.ID });
};
CrudComparer<Blah, Bleh>.UpdateOperation updateOperation = (leftObject, rightObject) =>
{
rightObject.BlehName = leftObject.BlahName;
};
CrudComparer<Blah, Bleh>.DeleteOperation deleteOperation = (rightObject, rightCollection) =>
{
rightCollection.Remove(rightObject);
};
CrudComparer<Blah, Bleh> cc = new CrudComparer<Blah, Bleh>(blahItems, blehItems, compareOperation, createOperation, updateOperation, deleteOperation);
cc.Compare();
}
I have been looking at this: http://code.msdn.microsoft.com/wpapps/Custom-LongList-Selector-bf8cb9ad and trying to incorporate into my app. However, its a little confusing since my data is loaded differently. Right now, I have two errors The best overloaded method match for CustomKeyGroup<.ViewModels.SoundData>.GetSoundGroups(System.Collections.Generic.List<.ViewModels.SoundData>)' has some invalid arguments
Argument 1: cannot convert from 'string' to 'System.Collections.Generic.List'
The error is at 'CustomKeyGroup.GetSoundGroups(mvm.Items);' from the mainpage.cs. I know the items is an issue. If you look at the link, they load the data differently w/ listmovie.add.
I know something is screwed up big time but since my data is loaded different, im struggling to get it working correctly.
Id like to have custom jumplist w/ headers by Groups (Alpha, Bravo, etc) located in my SoundModel. Here is a portion:
namespace T.ViewModels
{
public class SoundModel: BindableBase
{
public SoundGroup NewAdds { get; set; }
public SoundGroup Software { get; set; }
}
public bool IsDataLoaded { get; set; }
public void LoadData()
{
// Load data into the model
Software = CreateSoftwareGroup();
NewAdds = CreateNewAddsGroup();
IsDataLoaded = true;
}
private SoundGroup CreateNewAddsGroup()
{
SoundGroup data = new SoundGroup();
data.Title = "New";
string basePath = "assets/audio/newadds/";
data.Items.Add(new SoundData
{
Title = "Test1",
FilePath = basePath + "Test.mp3",
Groups = "Alpha"
});
data.Items.Add(new SoundData
{
Title = "Test2",
FilePath = basePath + "Test2.mp3",
Groups="Bravo"
});
data.Items.Add(new SoundData
{
Title = "Test3",
FilePath = basePath + "Test3.mp3",
Groups= "Zulu"
});
private SoundGroup CreateSoftwareGroup()
{
SoundGroup data = new SoundGroup();
data.Title = "Software";
string basePath = "assets/audio/Software/";
data.Items.Add(new SoundData
{
Title = "Test1",
FilePath = basePath + "Test.mp3",
Groups = "Alpha"
});
data.Items.Add(new SoundData
{
Title = "Test2",
FilePath = basePath + "Test2.mp3",
Groups="Bravo"
});
data.Items.Add(new SoundData
{
Title = "Test3",
FilePath = basePath + "Test3.mp3",
Groups= "Zulu"
});
Here is the relevant mainpage.cs:
SoundData mvm = new SoundData();
this.LongList.ItemsSource = CustomKeyGroup<SoundData>.GetSoundGroups(mvm.Items);
SoundGroup:
{
public class SoundGroup
{
public SoundGroup()
{
Items = new List<SoundData>();
}
public List<SoundData> Items { get; set; }
public string Title { get; set; }
public string Groups { get; set; }
}
}
SoundData :
{
public class SoundData : ViewModelBase
{
public string Title { get; set; }
public string FilePath { get; set; }
public string Items { get; set; }
public string Groups { get; set; }
public RelayCommand<string> SaveSoundAsRingtone { get; set; }
private void ExecuteSaveSoundAsRingtone(string soundPath)
{
App.Current.RootVisual.Dispatcher.BeginInvoke(() =>
{
SaveRingtoneTask task = new SaveRingtoneTask();
task.Source = new Uri("appdata:/" + this.FilePath);
task.DisplayName = this.Title;
task.Show();
}
);
}
public SoundData()
{
SaveSoundAsRingtone = new RelayCommand<string>(ExecuteSaveSoundAsRingtone);
}
}
}
So far from I what can see you should be calling the function as below
SoundModel svm = new SoundModel();
svm.LoadData();
this.LongList.ItemsSource = CustomKeyGroup<SoundData>.GetSoundGroups(svm.Software.Items);
or
this.LongList.ItemsSource = CustomKeyGroup<SoundData>.GetSoundGroups(svm.NewAdds.Items);
the reason is that you need to pass a Generic.List<.ViewModels.SoundData> in method GetSoundGroups and the list is contained in SoundGroup class. Since your data loaded is within SoundModel class so I could probably think of the above implementation only.