Gnome shell extension: not getting all properties from dbus - dbus

On my laptop:
gdbus introspect --system --dest org.freedesktop.UPower --object-path /org/freedesktop/UPower/devices/DisplayDevice
returns a set of properties:
properties:
readonly s NativePath = '';
readonly s Vendor = '';
readonly s Model = '';
readonly s Serial = '';
readonly t UpdateTime = 1669341757;
readonly u Type = 2;
readonly b PowerSupply = true;
readonly b HasHistory = false;
readonly b HasStatistics = false;
readonly b Online = false;
readonly d Energy = 32.719999999999999;
readonly d EnergyEmpty = 0.0;
readonly d EnergyFull = 58.990000000000002;
readonly d EnergyFullDesign = 0.0;
readonly d EnergyRate = 6.2569999999999997;
readonly d Voltage = 0.0;
readonly i ChargeCycles = 0;
readonly d Luminosity = 0.0;
readonly x TimeToEmpty = 18825;
readonly x TimeToFull = 0;
readonly d Percentage = 55.0;
readonly d Temperature = 0.0;
readonly b IsPresent = true;
readonly u State = 2;
readonly b IsRechargeable = false;
readonly d Capacity = 0.0;
readonly u Technology = 0;
readonly u WarningLevel = 1;
readonly u BatteryLevel = 1;
readonly s IconName = 'battery-good-symbolic';
I am trying to modify a gnome shell extension.
when initalising the extension, it does this:
const BUS_NAME = 'org.freedesktop.UPower';
const OBJECT_PATH = '/org/freedesktop/UPower/devices/DisplayDevice';
const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device'); // see https://upower.freedesktop.org/docs/UPower.html
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
...
this._proxy = new PowerManagerProxy(Gio.DBus.system, BUS_NAME, OBJECT_PATH,
...
the existing code accesses a couple of properties like this:
let chargingState = this._proxy.State === UPower.DeviceState.CHARGING
? '-charging' : '';
let fillLevel = 10 * Math.floor(this._proxy.Percentage / 10);
According to the documentation, there is another property EnergyRate
(https://upower.freedesktop.org/docs/UPower.html)
and the gdbus call (above) returns a value for many properties, including EnergyRate.
Yet when I do:
global.log("Energy: " + this._proxy.EnergyRate);
the value of the property EnergyRate is undefined.
This happens for other defined properties too, such as Energy
Why can't I access all of the properties?

I am new at this, which means this will be an "explain it like I'm five" because that's my mental age with respect to this.
Primitive solution
I came up with one solution which required only rudimentary knowledge of the gnome libraries, and #andy.holmes contributed an expert answer via comments.
The existing code sets up access to the dbus "address"/endpoint in two steps:
const DisplayDeviceInterface = loadInterfaceXML('org.freedesktop.UPower.Device');
and
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(DisplayDeviceInterface);
the first line refers to XML which is part of the gnome runtime.
The fragment is here https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/92d3c6e051958b31151bf9538205a71cab6f70d7/data/dbus-interfaces/org.freedesktop.UPower.Device.xml
and it has only a small subset of the properties of the dbus address.
Missing is energy-rate.
So I made a string, copying the gnome runtime XML and adding one line:
const UPowerInterface = '<node>\n' +
' <interface name="org.freedesktop.UPower.Device">\n' +
' <property name="Type" type="u" access="read"/>\n' +
' <property name="State" type="u" access="read"/>\n' +
' <property name="Percentage" type="d" access="read"/>\n' +
' <property name="EnergyRate" type="d" access="read"/>\n' +
' <property name="TimeToEmpty" type="x" access="read"/>\n' +
' <property name="TimeToFull" type="x" access="read"/>\n' +
' <property name="IsPresent" type="b" access="read"/>\n' +
' <property name="IconName" type="s" access="read"/>\n' +
' </interface>\n' +
'</node>\n'
and did this:
const PowerManagerProxy = Gio.DBusProxy.makeProxyWrapper(UPowerInterface);
and now I have a property EnergyRate. I don't know why these properties are missing, there may be a very good reason. I have asked Florian Mueller.
Expert Solution
#andy.holmes suggested a one-line alternative which does not need new XML nor any other changes:
let value = this._proxy.get_cached_property('EnergyRate')?.unpack() || 0;
and it works and it is less effort.

Related

Specified element is already a logical child of another element

I hope this doesn't get marked as duplicate since my problem is kinda complex, so none of the other answers helped. I have a class called 'ControlChoiceModule' that generates a System.Windows.Controls object based on the type of property it deals with (String - TextBox, Boolean - CheckBox, DateTime - DatePicker, etc..).
It has two dictionaries:
public static class ControlChoiceModule
{
private static readonly Dictionary<Type, object> TypeToControl = new Dictionary<Type, object>
{
{typeof(bool), new CheckBox() },
{typeof(DateTime), new DatePicker() }
};
private static readonly Dictionary<Type, DependencyProperty> ControlToProperty = new Dictionary<Type, DependencyProperty>
{
{typeof(TextBox), TextBox.TextProperty },
{typeof(CheckBox), CheckBox.IsCheckedProperty },
{typeof(DatePicker), DatePicker.SelectedDateProperty }
};
The purpose of the other one is just for binding. And here are the two methods:
public static object GenerateControl(Type theType, Binding B)
{
object O;
if (TypeToControl.ContainsKey(theType))
{
O = TypeToControl[theType];
}
else
{
O = new TextBox();
}
SetBinding(O, B);
return O;
}
private static void SetBinding(object O, Binding B)
{
BindingOperations.SetBinding(O as DependencyObject, ControlToProperty[O.GetType()], B);
}
Now the purpose of all this is to generate an insertion window for a certain class, generically. So the windows loops through all of the class's properties and, based on the type, generates an appropriate field for it.
private void GenerateInsertionOrUpdatePage(string windowText)
{
var w2 = new InsertionWindow();
w2.DataContext = this.DataContext;
w2.Title = windowText;
w2.Show();
foreach (var P in ReturnPropertyList())
{
if (P.Name != "SearchableString" && P.Name != "Id" )
{
Label L = new Label();
L.Content = P.Name + ":";
w2.InsertionStackPanel.Children.Add(L);
Binding B = new Binding();
B.Path = new PropertyPath("NewT." + P.Name);
B.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
B.Mode = BindingMode.TwoWay;
**w2.InsertionStackPanel.Children.Add(ControlChoiceModule.GenerateControl(P.PropertyType, B) as UIElement);**
}
}
}
The method above gets called on a click of a button. The first time I click it, it works just fine. But when I click it again, I get the error from the title (on the line marked with **).
Any idea why this happens?
Thanks

WPF DataGrid : How to add a row thats content is defined by an array of Object?

I have created several Datagrids dynamically. In the mode of dynamic Datagrid creation the number and name of columns are not known in advance.
So, I created a DataGrid like below :
DataGrid grid = new DataGrid();
grid.Columns.Add(new DataGridTextColumn() { Header = randomHeader1 });
grid.Columns.Add(new DataGridTextColumn() { Header = randomHeader2 });
grid.Columns.Add(new DataGridTextColumn() { Header = randomHeader3 });
// The number of columns for each datagrid is variable
How can I add rows to my Datagrid? For instance, I want to add those 3 rows to Dtatagrid that I have defined in the top:
a, b, c
d, e, f
g, h, i
I tried to solve my problem like below but it is not working:
grid.Items.Add(new Object[] { "a", "b", "c" });
grid.Items.Add(new Object[] { "d", "e", "f" });
grid.Items.Add(new Object[] { "g", "h", "i" });
Please review the code and provide me solution.
Using reflection, you could create a collection of dynamic objects, then bind your DataGrid to it.
There is a great answer here about creating dynamic classes:
How to dynamically create a class in C#?
Using this, you can create the list of properties (which will be columns in your datagrid) at runtime like this
List<TypeBuilderNamespace.Field> myFields = new List<TypeBuilderNamespace.Field>();
myFields.Add( new TypeBuilderNamespace.Field("FirstName", Type.GetType("System.String")));
myFields.Add( new TypeBuilderNamespace.Field("Surname", Type.GetType("System.String")));
myFields.Add( new TypeBuilderNamespace.Field("Age", Type.GetType("System.Int32")));
Then dynamically create your class
Type myDynamicType = TypeBuilderNamespace.MyTypeBuilder.CompileResultType(myFields);
Create some sample data
List<dynamic> people = new List<dynamic>();
dynamic person1 = Activator.CreateInstance(myDynamicType);
person1.FirstName = "John";
person1.Surname = "Smith";
person1.Age = 45;
people.Add(person1);
dynamic person2 = Activator.CreateInstance(myDynamicType);
person2.FirstName = "Emma";
person2.Surname = "Jones";
person2.Age = 18;
people.Add(person2);
Then bind your data to the grid
DataGrid grid = new DataGrid();
grid.AutoGenerateColumns = true;
grid.ItemsSource = people;
This gives the following DataGrid
I modified the code in the answer quoted above slightly, so here is my listing of that for completeness:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
namespace TypeBuilderNamespace {
public class Field {
public String FieldName { get; set; }
public Type FieldType { get; set; }
public Field(String name, Type type) {
FieldName = name;
FieldType = type;
}
}
public static class MyTypeBuilder {
public static Type CompileResultType(List<Field> fields) {
TypeBuilder tb = GetTypeBuilder();
ConstructorBuilder constructor = tb.DefineDefaultConstructor(MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName);
FieldName(string) and FieldType(Type)
foreach (var field in fields)
CreateProperty(tb, field.FieldName, field.FieldType);
Type objectType = tb.CreateType();
return objectType;
}
private static TypeBuilder GetTypeBuilder() {
var typeSignature = "MyDynamicType";
var an = new AssemblyName(typeSignature);
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType(typeSignature
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, null);
return tb;
}
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType) {
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, propertyType, FieldAttributes.Private);
PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName, MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, propertyType, Type.EmptyTypes);
ILGenerator getIl = getPropMthdBldr.GetILGenerator();
getIl.Emit(OpCodes.Ldarg_0);
getIl.Emit(OpCodes.Ldfld, fieldBuilder);
getIl.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
null, new[] { propertyType });
ILGenerator setIl = setPropMthdBldr.GetILGenerator();
Label modifyProperty = setIl.DefineLabel();
Label exitSet = setIl.DefineLabel();
setIl.MarkLabel(modifyProperty);
setIl.Emit(OpCodes.Ldarg_0);
setIl.Emit(OpCodes.Ldarg_1);
setIl.Emit(OpCodes.Stfld, fieldBuilder);
setIl.Emit(OpCodes.Nop);
setIl.MarkLabel(exitSet);
setIl.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
}
}
}

accessing array properties

var questions:Array = new Array;
questions[0] = "qname:mc_01, qvalue:1";
questions[1] = "qname:mc_02, qvalue:1";
questions[2] = "qname:mc_03, qvalue:1";
questions[3] = "qname:mc_04, qvalue:1";
questions[4] = "qname:mc_05, qvalue:1";
questions[5] = "qname:mc_06, qvalue:1";
questions[6] = "qname:mc_07, qvalue:1";
questions[7] = "qname:mc_08, qvalue:1";
questions[8] = "qname:mc_09, qvalue:1";
questions[9] = "qname:mc_10, qvalue:1";
questions[10] = "qname:mc_11, qvalue:2";
questions[11] = "qname:mc_12, qvalue:2";
questions[12] = "qname:mc_13, qvalue:2";
questions[13] = "qname:mc_14, qvalue:2";
questions[14] = "qname:mc_15, qvalue:2";
questions[15] = "qname:mc_16, qvalue:2";
questions[16] = "qname:mc_17, qvalue:2";
questions[17] = "qname:mc_18, qvalue:2";
questions[18] = "qname:mc_19, qvalue:2";
questions[19] = "qname:mc_20, qvalue:2";
questions[20] = "qname:mc_21, qvalue:3";
questions[21] = "qname:mc_22, qvalue:3";
questions[22] = "qname:mc_23, qvalue:3";
questions[23] = "qname:mc_24, qvalue:3";
questions[24] = "qname:mc_25, qvalue:3";
questions[25] = "qname:mc_26, qvalue:3";
questions[26] = "qname:mc_27, qvalue:3";
questions[27] = "qname:mc_28, qvalue:3";
questions[28] = "qname:mc_29, qvalue:3";
questions[29] = "qname:mc_30, qvalue:3";
I've got this array and want to access the qname property and can't remember how to do it. Is it something like questions[0].qname or questions[0](qname)?
You've defined your array elements as string instead of objects.
Try this instead:
var questions:Array = new Array;
questions[0] = {qname:mc_01, qvalue:1};
...
Curly braces instead of double-quotation marks. With quotation marks you create strings. With curly braces, you can create dynamic objects and set their properties. So if you are creating a string value for qname, make sure you define it as qname:"mc_01" instead of qname:mc_01.
So you can use questions[0].qname or questions[0]["qname"] to access the properties.
But if you can't do that what is told in previous answer (e.g. you get those strings from server) you can use regular expresions to get those values nicely:
var searchPattern : RegExp = /(?P<qname>(?<=qname\:)[a-zA-Z0-9_]+(?=[\s,]*))/g;
trace( searchPattern.exec(questions[1]).qname ); // traces out: mc_02
As you tagged ActionScript 3.0, and its a strongly typed language, I would recommend a typed class to hold your data structure.
package your.package.name
{
public class Question
{
protected var _name:String;
protected var _value:String;
public function Question(name:String = null, value:String = null)
{
this.name = name;
this.value = value;
}
public function get name():String
{
return _name;
}
public function set name(value:String):void
{
_name = value;
}
public function get value():String
{
return _value;
}
public function set value(value:String):void
{
_value = value;
}
}
}
By having getters and setters and also exposing these props in the constructor you can create them in two ways:
var question:Question = new Question("Question1", "Question value");
OR:
var question:Question = new Question();
question.name = "Question1";
question.value = "Question value";
This offers benefits in terms of intellisense for getting properties in your ide and also type safety to stop you putting in incorrect types for name and value.
Then to get hold of a question:
questions[0].name; // in this example Question1
questions[0].value; // in this example Question value
Usually your questions would be coming from some data source, like xml or a web service, whatever I'll use literal xml for this example, in that scenario you would want to build your objects in some loop eg:
var questionsXML:XML =
<questions>
<question name="Question1">Question1 value</question>
<question name="Question2">Question2 value</question>
<question name="Question3">Question3 value</question>
</questions>
Then:
var questions:Array = [];
for each (var questionXML:XML in questionsXML.question)
{
var question:Question = new Question();
question.name = questionXML.#name;
question.value = questionXML.text();
questions.push(question);
}

how to update a datagridview on a Parent form from a Child Form C#

I'm quite a new C# programmer,it has been a month that ive started using C#, so far so good i might say, but im curently dealing with a simple situation , but i still dont get it to work , there is the scenario :
I've 2 forms a Parent and a Child , the parent contains a Xtragrid control and a button which opens the second form and load the textBoxes in the second form with values , the second has a button to update the values in case of any changes . but i still dont get it to work , I've the following error :
MUST DECLARE A SCALAR VARIABLE at #ID
I understood the cause of the probleme but i just cant fix it ,ive have done some researches to sort myself out but i still didnt manage to make it work
the last line
da.updatecommand.parameters.addwithvalues("ID#",ds.tables["tblLesseeYW"].Rows[LesseeYW.Position][0];
I have done it but it is not working( LesseeYW which is my binding source object but it doesnt exit in the current context nor the dataset which is understandable
: there is the code need help pleaese
// This the class ive created to retrieve all Columns from the SQl server data base
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace YoungWoman
{
public static class GetRowData
{
public static int LesseeId;
public static byte LesseePic;
public static string LesseeName;
public static string LesseeLastName;
public static string PassportNo;
public static string IDNo;
public static DateTime BirthDate;
public static string Gender;
public static string Country;
public static string City;
public static string Province;
public static string LesseePostalCode;
public static string MobileNo;
public static string HomePhoneNo;
public static string TutorName;
public static string TutorLastName;
public static string AddressTutor;
public static string AddressLessee;
public static string TutorPhoneNo;
public static string TutorEmail;
}
}
// the parent form
namespace YoungWoman
{
public partial class Lessee2 : UserControl
{
DataSet ds = new DataSet();
DataView dv ;
SqlDataAdapter daLessee = new SqlDataAdapter();
SqlDataAdapter daReservation = new SqlDataAdapter();
BindingSource LesseeYW = new BindingSource();
BindingSource ReservationCenterYW = new BindingSource();
SqlConnection conne = SqlCoonectionSEtup.GetConnection;
// the button that opens the Child Form
private void EditLesseeFrm_Click(object sender, EventArgs e)
{
Lesseefrm Lessee = new Lesseefrm(Utils.Formtype.edit, 1);
Lessee.LesseeEventHandler += new EventHandler(RefreshLesseeGrid);
GetRowData.LesseeId = Convert.ToInt32(gridView1.GetRowCellValue (gridView1.FocusedRowHandle, "LesseeId"));
GetRowData.LesseeName = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "LesseeName"));
GetRowData.LesseeLastName = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle,"LesseeLastName"));
GetRowData.PassportNo = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle,"PassportNo"));
GetRowData.Gender = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "Gender"));
GetRowData.Province = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "Province"));
GetRowData.BirthDate = Convert.ToDateTime(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "BirthDate"));
GetRowData.City = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "City"));
GetRowData.Country = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "Country"));
GetRowData.MobileNo = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "MobileNo"));
GetRowData.HomePhoneNo = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "HomePhoneNo"));
GetRowData.IDNo = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "IDNo"));
GetRowData.AddressLessee = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "AddressLessee"));
GetRowData.AddressTutor = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "AddressTutor"));
GetRowData.LesseePostalCode = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "LesseePostalCode"));
GetRowData.TutorName = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "TutorName"));
GetRowData.TutorLastName = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "TutorLastName"));
GetRowData.TutorPhoneNo = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "TutorPhoneNo"));
GetRowData.TutorEmail = Convert.ToString(gridView1.GetRowCellValue(gridView1.FocusedRowHandle, "TutorEmail"));
Lessee.ShowDialog();
}
( // Child LOad_form if form type == Edit )
if (formtype == Formtype.edit && Lesseeid > 0)
{
LesseeIdtextEdit.Enabled = false;
ClearBtnlayoutControlItem26.Visibility = DevExpress.XtraLayout.Utils.LayoutVisibility.Never;
SaveBtn.Text = "&Edit";
SaveBtn.Image = Resources.brush_16;
this.Text = string.Format(" Edit Lessee Information - YW Residence ");
LesseeIdtextEdit.Text = Convert.ToInt32(GetRowData.LesseeId).ToString();
txtName.Text = GetRowData.LesseeName;
txtLAstname.Text = GetRowData.LesseeLastName;
txtPassport.Text = GetRowData.PassportNo;
txtID.Text = GetRowData.IDNo;
GendercomboBoxEdit.SelectedItem = GetRowData.Gender;
DobdateEdit.DateTime = GetRowData.BirthDate;
CountrycomboBoxEdit.SelectedItem = GetRowData.Country;
txtProvince.Text = GetRowData.Province;
txtCity.Text = GetRowData.City;
txtPostalCode.Text = GetRowData.LesseePostalCode;
LesseememoEdit1.Text = GetRowData.AddressLessee;
txtMobile.Text = GetRowData.MobileNo;
txtHomePhone.Text = GetRowData.HomePhoneNo;
txtTutorName.Text = GetRowData.TutorName;
txttutorLastname.Text = GetRowData.TutorLastName;
tutorAddresstxt.Text = GetRowData.AddressTutor;
txtTutorMobile.Text = GetRowData.TutorPhoneNo;
txtEmail.Text = GetRowData.TutorEmail;
}
public event System.EventHandler LesseeEventHandler;
private void SaveBtn_Click(object sender, EventArgs e)
if (formtype == Formtype.edit && Lesseeid > 0)
{
MemoryStream ms = new MemoryStream();
PicBox1.Image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] Pic_arr = new byte[ms.Length];
ms.Position = 0;
ms.Read(Pic_arr, 0, Pic_arr.Length);
try
{
da.UpdateCommand = new SqlCommand(" UPDATE LesseeYW SET LesseePic = #image , LesseeName = #Name, LesseeLastName = #Last , PassportNo = #pass,IDNo = #Number, BirthDate =#birth ,Gender = #gender , Country =#country,LesseePostalCode = #Postal,City = #city , Province = #province,MobileNo = #Mobile,HomePhoneNo = #phone,TutorName = #tutor,TutorLastName=#Tlast,AddressTutor = #line1,AddressLessee=#line2,TutorPhoneNo = #Tphone,TutorEmail =#Temail WHERE LesseeId = #ID ", conne);
da.UpdateCommand.Parameters.AddWithValue("#image", Pic_arr);
da.UpdateCommand.Parameters.AddWithValue("#Name", txtName.Text);
da.UpdateCommand.Parameters.AddWithValue("#Last", txtLAstname.Text);
da.UpdateCommand.Parameters.AddWithValue("#pass", txtPassport.Text);
da.UpdateCommand.Parameters.AddWithValue("#Number", txtID.Text);
da.UpdateCommand.Parameters.AddWithValue("#birth", DobdateEdit.DateTime);
da.UpdateCommand.Parameters.AddWithValue("#gender", GendercomboBoxEdit.SelectedItem.ToString());
da.UpdateCommand.Parameters.AddWithValue("#country", CountrycomboBoxEdit.SelectedItem.ToString());
da.UpdateCommand.Parameters.AddWithValue("#Postal", txtPostalCode.Text);
da.UpdateCommand.Parameters.AddWithValue("#city", txtCity.Text);
da.UpdateCommand.Parameters.AddWithValue("#province", txtProvince.Text);
da.UpdateCommand.Parameters.AddWithValue("#Mobile", txtMobile.Text);
da.UpdateCommand.Parameters.AddWithValue("#phone", txtHomePhone.Text);
da.UpdateCommand.Parameters.AddWithValue("#tutor", txtTutorName.Text);
da.UpdateCommand.Parameters.AddWithValue("#Tlast", txttutorLastname.Text);
da.UpdateCommand.Parameters.AddWithValue("#line1", tutorAddresstxt.Text);
da.UpdateCommand.Parameters.AddWithValue("#line2", LesseememoEdit1.Text);
da.UpdateCommand.Parameters.AddWithValue("#Tphone", txtTutorMobile.Text);
da.UpdateCommand.Parameters.AddWithValue("#Temail", txtEmail.Text);
//da.UpdateCommand.Parameters.AddWithValue("#ID"
da.UpdateCommand.ExecuteNonQuery();
conne.Close();
MessageBox.Show("Lessee Details Updated ", "Confirmation", MessageBoxButtons.OK, MessageBoxIcon.Information);
this.Close();
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
at first you should program more objective. Dont declare all variables of your class as public static. You should make them private. To get acces you have to declare Properties.
Like this:
private string name;
public string Name
{
get {return name;}
set {name = value;}
}
if you have an ID you can easily make it read-only and noone from "outside" can modify it but everyone can read.
private int leeseId;
public int LeeseID
{
get{return leeseId;}
}
So you use "getter/setter" to offer your class properties. Further not all your variables should named leese... Just name it id,name,city,pic etc. In your form you create an Object from your class. You can name this object Leese.
private Leese leese = new Leese();
leese.id = ???
leese.name = ???
Much more readable.
da.updatecommand.parameters.addwithvalues("ID#",ds.tables["tblLesseeYW"].Rows[LesseeYW.Position][0];
You wrote "ID#" but it should be "#ID". And if you build your class as i descripe at top you can use property:
da.updatecommand.parameters.addwithvalues("#ID", leese.Id);
i hope that help you.

Ignoring properties in Dapper

In Dapper (http://code.google.com/p/dapper-dot-net/), is there a way to ignore properties in the model class, namely when using the Insert extension method?
My model class has a set of computed properties which are not persisted in the associated table.
Well, Dapper has no Insert extension method, that is in dapper.contrib, dapper extensions or dapper rainbow.
Dapper itself allows you to do:
Animal a = new Animal {Age = 10, Family = "Canine"}
// only insert Age
cnn.Execute("insert Animal(Age) values (#Age)", a);
To work around for some of the extension classes you can sometimes do:
cnn.InsertExtension("Animal", new{a.Age});
Regardless, you can always fall back to raw Dapper for your complex filtered inserts.
If you are using Dapper.Contrib, check out this code in SqlMapperExtensions:
https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper.Contrib/SqlMapperExtensions.cs#L54-L66
private static List<PropertyInfo> ComputedPropertiesCache(Type type)
{
//...
var computedProperties = TypePropertiesCache(type).Where(p => p.GetCustomAttributes(true).Any(a => a is ComputedAttribute)).ToList();
and https://github.com/StackExchange/dapper-dot-net/blob/master/Dapper.Contrib/SqlMapperExtensions.Async.cs#L147-L165
var computedProperties = ComputedPropertiesCache(type);
var allPropertiesExceptKeyAndComputed = allProperties.Except(keyProperties.Union(computedProperties)).ToList();
//...
for (var i = 0; i < allPropertiesExceptKeyAndComputed.Count; i++)
{
//...
So if you add a ComputedAttribute to your properties on your class, Dapper.Contrib won't try to insert them in to the database! You shouldn't have to worry about getting Dapper to ignore those properties, only Dapper.Contrib. Because if you use select * from tablename in your dapper queries,it will only try to map columns that exist. So you just don't create columns for the properties which you marked as [Computed].
Just add the [Computed] attribute to the properties in question.
If you just want to "hide" a property from your Insert/Update statements then there is one official way to do this in dapper extensions:
using DapperExtensions.Mapper;
public class UserMapper : ClassMapper<User>
{
public UserMapper()
{
base.Map(m => m.IsTrialUser).Ignore();
base.AutoMap();
}
}
I wrote a modified version of the SqlMapperExtensions class and added a string[] parameter ExcludeProperties for excluding columns. Using this class you can make calls like:
// Insert
result = (int)cn.Insert<Animal>(box, new string[] { "Errors", "IsValid" });
// Update
cn.UpdateEntity<Animal>(box, new string[] { "Errors", "IsValid" });
In the statements above, the 'Errors' and 'IsValid' properties I added for will not be included in the SQL statements.
Here's the modified extensions class:
SqlMapperExtensions.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Collections.Concurrent;
using System.Reflection.Emit;
using System.Threading;
using System.Runtime.CompilerServices;
namespace Dapper.Contrib.Extensions
{
public static class SqlMapperExtensions
{
public interface IProxy
{
bool IsDirty { get; set; }
}
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> KeyProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> TypeProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>();
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> GetQueries = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static readonly ConcurrentDictionary<RuntimeTypeHandle, string> TypeTableName = new ConcurrentDictionary<RuntimeTypeHandle, string>();
private static IEnumerable<PropertyInfo> KeyPropertiesCache(Type type)
{
if (KeyProperties.ContainsKey(type.TypeHandle))
{
return KeyProperties[type.TypeHandle];
}
var allProperties = TypePropertiesCache(type);
var keyProperties = allProperties.Where(p => p.GetCustomAttributes(true).Any(a => a is KeyAttribute)).ToList();
if (keyProperties.Count == 0)
{
var idProp = allProperties.Where(p => p.Name.ToLower() == "id" || p.Name.ToLower() == (type.Name.ToLower() + "id")).FirstOrDefault();
if (idProp != null)
{
keyProperties.Add(idProp);
}
}
KeyProperties[type.TypeHandle] = keyProperties;
return keyProperties;
}
private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type)
{
if (TypeProperties.ContainsKey(type.TypeHandle))
{
return TypeProperties[type.TypeHandle];
}
var properties = type.GetProperties();
TypeProperties[type.TypeHandle] = properties;
return properties;
}
/// <summary>
/// Returns a single entity by a single id from table "Ts". T must be of interface type.
/// Id must be marked with [Key] attribute.
/// Created entity is tracked/intercepted for changes and used by the Update() extension.
/// </summary>
/// <typeparam name="T">Interface type to create and populate</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="id">Id of the entity to get, must be marked with [Key] attribute</param>
/// <returns>Entity of T</returns>
public static T GetEntity<T>(this IDbConnection connection, dynamic id, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var type = typeof(T);
string sql;
if (!GetQueries.TryGetValue(type.TypeHandle, out sql))
{
var keys = KeyPropertiesCache(type);
if (keys.Count() > 1)
throw new DataException("Get<T> only supports an entity with a single [Key] property");
if (keys.Count() == 0)
throw new DataException("Get<T> only supports en entity with a [Key] property");
var onlyKey = keys.First();
var name = GetTableName(type);
// TODO: pluralizer
// TODO: query information schema and only select fields that are both in information schema and underlying class / interface
sql = "select * from " + name + " where " + onlyKey.Name + " = #id";
GetQueries[type.TypeHandle] = sql;
}
var dynParms = new DynamicParameters();
dynParms.Add("#id", id);
T obj = null;
if (type.IsInterface)
{
var res = connection.Query(sql, dynParms).FirstOrDefault() as IDictionary<string, object>;
if (res == null)
return (T)((object)null);
obj = ProxyGenerator.GetInterfaceProxy<T>();
foreach (var property in TypePropertiesCache(type))
{
var val = res[property.Name];
property.SetValue(obj, val, null);
}
((IProxy)obj).IsDirty = false; //reset change tracking and return
}
else
{
obj = connection.Query<T>(sql, dynParms, transaction: transaction, commandTimeout: commandTimeout).FirstOrDefault();
}
return obj;
}
private static string GetTableName(Type type)
{
string name;
if (!TypeTableName.TryGetValue(type.TypeHandle, out name))
{
//name = type.Name + "s";
name = type.Name;
if (type.IsInterface && name.StartsWith("I"))
name = name.Substring(1);
//NOTE: This as dynamic trick should be able to handle both our own Table-attribute as well as the one in EntityFramework
var tableattr = type.GetCustomAttributes(false).Where(attr => attr.GetType().Name == "TableAttribute").SingleOrDefault() as
dynamic;
if (tableattr != null)
name = tableattr.Name;
TypeTableName[type.TypeHandle] = name;
}
return name;
}
/// <summary>
/// Inserts an entity into table "Ts" and returns identity id.
/// </summary>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToInsert">Entity to insert</param>
/// <returns>Identity of inserted entity</returns>
public static long Insert<T>(this IDbConnection connection, T entityToInsert, string[] ExcludeProperties = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
//using (var tx = connection.BeginTransaction())
//{
var type = typeof(T);
var name = GetTableName(type);
var sb = new StringBuilder(null);
sb.AppendFormat("insert into {0} (", name);
var allProperties = TypePropertiesCache(type);
if (ExcludeProperties != null)
{
List<PropertyInfo> someProperties = allProperties.ToList();
foreach (PropertyInfo prop in allProperties.ToArray())
{
if (ExcludeProperties.Contains(prop.Name))
{
someProperties.Remove(prop);
}
}
allProperties = someProperties.AsEnumerable();
}
var keyProperties = KeyPropertiesCache(type);
for (var i = 0; i < allProperties.Count(); i++)
{
var property = allProperties.ElementAt(i);
if (keyProperties.Contains(property)) continue;
sb.Append(property.Name);
if (i < allProperties.Count() - 1)
sb.Append(", ");
}
sb.Append(") values (");
for (var i = 0; i < allProperties.Count(); i++)
{
var property = allProperties.ElementAt(i);
if (keyProperties.Contains(property)) continue;
sb.AppendFormat("#{0}", property.Name);
if (i < allProperties.Count() - 1)
sb.Append(", ");
}
sb.Append(") ");
connection.Execute(sb.ToString(), entityToInsert, transaction: transaction, commandTimeout: commandTimeout);
//NOTE: would prefer to use IDENT_CURRENT('tablename') or IDENT_SCOPE but these are not available on SQLCE
var r = connection.Query("select ##IDENTITY id");
//tx.Commit();
return (int)r.First().id;
//}
}
/// <summary>
/// Updates entity in table "Ts", checks if the entity is modified if the entity is tracked by the Get() extension.
/// </summary>
/// <typeparam name="T">Type to be updated</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToUpdate">Entity to be updated</param>
/// <returns>true if updated, false if not found or not modified (tracked entities)</returns>
public static bool UpdateEntity<T>(this IDbConnection connection, T entityToUpdate, string[] ExcludeProperties = null, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var proxy = entityToUpdate as IProxy;
if (proxy != null)
{
if (!proxy.IsDirty) return false;
}
var type = typeof(T);
var keyProperties = KeyPropertiesCache(type);
if (keyProperties.Count() == 0)
throw new ArgumentException("Entity must have at least one [Key] property");
var name = GetTableName(type);
var sb = new StringBuilder();
sb.AppendFormat("update {0} set ", name);
var allProperties = TypePropertiesCache(type);
if (ExcludeProperties != null)
{
List<PropertyInfo> someProperties = allProperties.ToList();
foreach (PropertyInfo prop in allProperties.ToArray())
{
if (ExcludeProperties.Contains(prop.Name))
{
someProperties.Remove(prop);
}
}
allProperties = someProperties.AsEnumerable();
}
var nonIdProps = allProperties.Where(a => !keyProperties.Contains(a));
for (var i = 0; i < nonIdProps.Count(); i++)
{
var property = nonIdProps.ElementAt(i);
sb.AppendFormat("{0} = #{1}", property.Name, property.Name);
if (i < nonIdProps.Count() - 1)
sb.AppendFormat(", ");
}
sb.Append(" where ");
for (var i = 0; i < keyProperties.Count(); i++)
{
var property = keyProperties.ElementAt(i);
sb.AppendFormat("{0} = #{1}", property.Name, property.Name);
if (i < keyProperties.Count() - 1)
sb.AppendFormat(" and ");
}
var updated = connection.Execute(sb.ToString(), entityToUpdate, commandTimeout: commandTimeout, transaction: transaction);
return updated > 0;
}
/// <summary>
/// Delete entity in table "Ts".
/// </summary>
/// <typeparam name="T">Type of entity</typeparam>
/// <param name="connection">Open SqlConnection</param>
/// <param name="entityToDelete">Entity to delete</param>
/// <returns>true if deleted, false if not found</returns>
public static bool Delete<T>(this IDbConnection connection, T entityToDelete, IDbTransaction transaction = null, int? commandTimeout = null) where T : class
{
var type = typeof(T);
var keyProperties = KeyPropertiesCache(type);
if (keyProperties.Count() == 0)
throw new ArgumentException("Entity must have at least one [Key] property");
var name = GetTableName(type);
var sb = new StringBuilder();
sb.AppendFormat("delete from {0} where ", name);
for (var i = 0; i < keyProperties.Count(); i++)
{
var property = keyProperties.ElementAt(i);
sb.AppendFormat("{0} = #{1}", property.Name, property.Name);
if (i < keyProperties.Count() - 1)
sb.AppendFormat(" and ");
}
var deleted = connection.Execute(sb.ToString(), entityToDelete, transaction: transaction, commandTimeout: commandTimeout);
return deleted > 0;
}
class ProxyGenerator
{
private static readonly Dictionary<Type, object> TypeCache = new Dictionary<Type, object>();
private static AssemblyBuilder GetAsmBuilder(string name)
{
var assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(new AssemblyName { Name = name },
AssemblyBuilderAccess.Run); //NOTE: to save, use RunAndSave
return assemblyBuilder;
}
public static T GetClassProxy<T>()
{
// A class proxy could be implemented if all properties are virtual
// otherwise there is a pretty dangerous case where internal actions will not update dirty tracking
throw new NotImplementedException();
}
public static T GetInterfaceProxy<T>()
{
Type typeOfT = typeof(T);
if (TypeCache.ContainsKey(typeOfT))
{
return (T)TypeCache[typeOfT];
}
var assemblyBuilder = GetAsmBuilder(typeOfT.Name);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("SqlMapperExtensions." + typeOfT.Name); //NOTE: to save, add "asdasd.dll" parameter
var interfaceType = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy);
var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "_" + Guid.NewGuid(),
TypeAttributes.Public | TypeAttributes.Class);
typeBuilder.AddInterfaceImplementation(typeOfT);
typeBuilder.AddInterfaceImplementation(interfaceType);
//create our _isDirty field, which implements IProxy
var setIsDirtyMethod = CreateIsDirtyProperty(typeBuilder);
// Generate a field for each property, which implements the T
foreach (var property in typeof(T).GetProperties())
{
var isId = property.GetCustomAttributes(true).Any(a => a is KeyAttribute);
CreateProperty<T>(typeBuilder, property.Name, property.PropertyType, setIsDirtyMethod, isId);
}
var generatedType = typeBuilder.CreateType();
//assemblyBuilder.Save(name + ".dll"); //NOTE: to save, uncomment
var generatedObject = Activator.CreateInstance(generatedType);
TypeCache.Add(typeOfT, generatedObject);
return (T)generatedObject;
}
private static MethodInfo CreateIsDirtyProperty(TypeBuilder typeBuilder)
{
var propType = typeof(bool);
var field = typeBuilder.DefineField("_" + "IsDirty", propType, FieldAttributes.Private);
var property = typeBuilder.DefineProperty("IsDirty",
System.Reflection.PropertyAttributes.None,
propType,
new Type[] { propType });
const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.NewSlot | MethodAttributes.SpecialName |
MethodAttributes.Final | MethodAttributes.Virtual | MethodAttributes.HideBySig;
// Define the "get" and "set" accessor methods
var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + "IsDirty",
getSetAttr,
propType,
Type.EmptyTypes);
var currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + "IsDirty",
getSetAttr,
null,
new Type[] { propType });
var currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
var getMethod = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy).GetMethod("get_" + "IsDirty");
var setMethod = typeof(Dapper.Contrib.Extensions.SqlMapperExtensions.IProxy).GetMethod("set_" + "IsDirty");
typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
return currSetPropMthdBldr;
}
private static void CreateProperty<T>(TypeBuilder typeBuilder, string propertyName, Type propType, MethodInfo setIsDirtyMethod, bool isIdentity)
{
//Define the field and the property
var field = typeBuilder.DefineField("_" + propertyName, propType, FieldAttributes.Private);
var property = typeBuilder.DefineProperty(propertyName,
System.Reflection.PropertyAttributes.None,
propType,
new Type[] { propType });
const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.Virtual |
MethodAttributes.HideBySig;
// Define the "get" and "set" accessor methods
var currGetPropMthdBldr = typeBuilder.DefineMethod("get_" + propertyName,
getSetAttr,
propType,
Type.EmptyTypes);
var currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);
var currSetPropMthdBldr = typeBuilder.DefineMethod("set_" + propertyName,
getSetAttr,
null,
new Type[] { propType });
//store value in private field and set the isdirty flag
var currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldc_I4_1);
currSetIL.Emit(OpCodes.Call, setIsDirtyMethod);
currSetIL.Emit(OpCodes.Ret);
//TODO: Should copy all attributes defined by the interface?
if (isIdentity)
{
var keyAttribute = typeof(KeyAttribute);
var myConstructorInfo = keyAttribute.GetConstructor(new Type[] { });
var attributeBuilder = new CustomAttributeBuilder(myConstructorInfo, new object[] { });
property.SetCustomAttribute(attributeBuilder);
}
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
var getMethod = typeof(T).GetMethod("get_" + propertyName);
var setMethod = typeof(T).GetMethod("set_" + propertyName);
typeBuilder.DefineMethodOverride(currGetPropMthdBldr, getMethod);
typeBuilder.DefineMethodOverride(currSetPropMthdBldr, setMethod);
}
}
}
[AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute
{
public TableAttribute(string tableName)
{
Name = tableName;
}
public string Name { get; private set; }
}
}
I wrote a lightweight ORM that's an extension of Dapper. It actually does what you need. If you leave off the "Member" attribute of the property, the ORM will exclude it from the Insert.
You can access it at https://www.github.com/ricericebaby/ADOCRUD

Resources