Dynamic DataGridViewComboBox Column - custom-controls

I am trying to make a DataGridViewComboBox Column that will accept new data and add it to it's list items.
I am building this for a quoting system I sort of did this another way but I just couldn't get it to function reliably.
I keep getting a System.NullReferenceException on the OnSelectedIndexChanged.
I want to be able to type a value into the the ComboBox cell have it added to the list items in order.
Can someone help me out on this?
#region DataGridViewVariableComboBoxColumn
public class DataGridViewVariableComboBoxColumn : DataGridViewComboBoxColumn
{
[Browsable(true)]
[Category("Behavior")]
[DefaultValue(false)]
public bool AddNewItems { get; set; }
private System.Windows.Forms.AutoCompleteMode comboxAutoCompleteMode;
[Browsable(true)]
[Category("Behavior")]
[DefaultValue(false)]
public System.Windows.Forms.AutoCompleteMode ComboBoxAutoCompleteMode
{
get { return comboxAutoCompleteMode; }
set
{
comboxAutoCompleteMode = value;
}
}
public DataGridViewVariableComboBoxColumn()
{
this.CellTemplate = new DataGridViewVariableComboBoxCell();
}
public override DataGridViewCell CellTemplate
{
get
{
return base.CellTemplate;
}
set
{
if (value != null &&
!value.GetType().IsAssignableFrom(typeof(DataGridViewVariableComboBoxCell)))
{
throw new InvalidCastException("Must be a DataGridViewVariableComboBoxCell");
}
base.CellTemplate = value;
}
}
public override object Clone()
{
var c = (DataGridViewVariableComboBoxColumn)base.Clone();
if (c != null)
{
c.AddNewItems = this.AddNewItems;
c.ComboBoxAutoCompleteMode = this.ComboBoxAutoCompleteMode;
c.DisplayStyle = this.DisplayStyle;
c.FlatStyle = this.FlatStyle;
}
return c;
}
}
public class DataGridViewVariableComboBoxCell : DataGridViewComboBoxCell
{
public DataGridViewVariableComboBoxCell() : base()
{
}
public override object Clone()
{
DataGridViewVariableComboBoxCell cell = base.Clone() as DataGridViewVariableComboBoxCell;
return cell;
}
public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
try
{
base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
DataGridViewVariableComboBoxEditingControl TheControl = (DataGridViewVariableComboBoxEditingControl)DataGridView.EditingControl;
var c = (DataGridViewVariableComboBoxColumn)this.OwningColumn;
TheControl.OwningColumn = this.OwningColumn;
TheControl.AddNewItems = c.AddNewItems;
TheControl.EditingComboBoxAutoCompleteMode = c.ComboBoxAutoCompleteMode;
TheControl.EditingAutoCompleteSource = AutoCompleteSource.ListItems;
TheControl.EditingComboBoxStyle = ComboBoxStyle.DropDown;
if (TheControl != null)
{
TheControl.SelectedIndex = 0;
}
}
catch { }
}
public override Type EditType
{
get
{
return typeof(DataGridViewVariableComboBoxEditingControl);
}
}
public override Type ValueType
{
get
{
// Return the type of the value that DataGridViewVariableComboBoxCell contains.
return typeof(string);
}
}
}
internal class DataGridViewVariableComboBoxEditingControl : DataGridViewComboBoxEditingControl, IDataGridViewEditingControl
{
private DataGridView dataGridViewControl;
private int rowIndex;
private bool valueChanged = false;
public System.Windows.Forms.AutoCompleteMode EditingComboBoxAutoCompleteMode
{
get
{return this.AutoCompleteMode; }
set
{
this.AutoCompleteMode = value;
}
}
public ComboBoxStyle EditingComboBoxStyle
{
get
{ return this.DropDownStyle; }
set
{
this.DropDownStyle = value;
}
}
public AutoCompleteSource EditingAutoCompleteSource
{
get
{ return this.AutoCompleteSource; }
set
{
this.AutoCompleteSource = value;
}
}
public DataGridViewVariableComboBoxEditingControl() : base()
{
}
public bool AddNewItems { get; set; }
public DataGridViewColumn OwningColumn { get; set; }
private string editingControlFormattedValue;
public string EditingControlFormattedValue
{
get
{
return editingControlFormattedValue;
}
set
{
editingControlFormattedValue = value;
}
}
public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
editingControlFormattedValue = this.Text;
if (this.SelectedIndex == -1 && this.AddNewItems && editingControlFormattedValue != "")
{
List<string> list = new List<string>();
if (this.Items.Count > 0)
{
list = this.Items.Cast<string>()
.Select(x => x)
.ToList();
}
else
{
list = new List<string>();
}
if (!list.Contains(editingControlFormattedValue) && editingControlFormattedValue != "")
{
list.Add(editingControlFormattedValue);
list = list.Distinct().OrderBy(o => o).ToList();
}
((DataGridViewVariableComboBoxColumn)OwningColumn).Items.Clear();
((DataGridViewVariableComboBoxColumn)OwningColumn).Items.AddRange(list.ToArray());
this.Items.Clear();
this.Items.AddRange(list.ToArray());
int index = ((DataGridViewVariableComboBoxColumn)OwningColumn).Items.IndexOf(editingControlFormattedValue);
EditingControlValueChanged = true;
//base.SelectedIndex = index;
//this.Text = text;
// EditingControlDataGridView.NotifyCurrentCellDirty(true);
}
return editingControlFormattedValue;
}
public DataGridView EditingControlDataGridView
{
get
{
return dataGridViewControl;
}
set
{
dataGridViewControl = value;
}
}
public int EditingControlRowIndex
{
get
{
return rowIndex;
}
set
{
rowIndex = value;
}
}
public bool EditingControlWantsInputKey(
Keys key, bool dataGridViewWantsInputKey)
{
// Let the DateTimePicker handle the keys listed.
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true;
default:
return false;
}
}
// Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit
// method.
public void PrepareEditingControlForEdit(bool selectAll)
{
// No preparation needs to be done.
}
// Implements the IDataGridViewEditingControl
// .RepositionEditingControlOnValueChange property.
public bool RepositionEditingControlOnValueChange
{
get
{
return false;
}
}
// Implements the IDataGridViewEditingControl
// .EditingControlValueChanged property.
public bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
valueChanged = value;
}
}
// Implements the IDataGridViewEditingControl
// .EditingPanelCursor property.
public Cursor EditingPanelCursor
{
get
{
return base.Cursor;
}
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (valueChanged)
{
base.OnSelectedIndexChanged(e);
}
}
protected override void OnSelectedValueChanged(EventArgs e)
{
if (valueChanged)
{
base.OnSelectedValueChanged(e);
}
}
protected override void OnSelectedItemChanged(EventArgs e)
{
if (valueChanged)
{
base.OnSelectedItemChanged(e);
}
}
}
#endregion

Related

Error when migrating WCF service to gRPC service

I have a WCF service that I want to rewrite into a gRPC service. There is a specific endpoint that gives me some trouble. Right now the method looks like this:
public List<Dictionary<string, string> GetData(GetDataRequest request)
{
List<Dictionary<string, string>> results = new List<Dictionary<string, string>>();
/// ...
/// Code that populates the results list
/// ...
return results;
}
I have composed the proto file like this:
message GetDataRequest {
string code = 1;
}
message GetDataResponse {
message KeyValuePair {
map<string, string> pairs = 1;
}
repeated KeyValuePair results= 1;
}
service Demo {
rpc GetData(GetDataRequest) returns (GetDataResponse);
}
And the service implementation:
public class DemoService : Demo.DemoBase
{
public override async Task<GetDataResponse> GetData(GetDataRequest request, ServerCallContext context)
{
List<Dictionary<string, string>> results = new List<Dictionary<string, string>>();
/// ...
/// Code that populates the results list
/// ...
return await Task.FromResult(new GetDataResponse
{
Results = results
});
}
}
My problem is when I try to return the list of dictionaries I get the this error:
What changes I need to make in order to return the response properly?
I use the Visual Studio 2019 gRPC Service template.
This is the GetDataResponse generated code from protobuf compiler:
public sealed partial class GetDataResponse : pb::IMessage<GetDataResponse>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<GetDataResponse> _parser = new pb::MessageParser<GetDataResponse>(() => new GetDataResponse());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<GetDataResponse> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GrpcService.Protos.DemoReflection.Descriptor.MessageTypes[1]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse(GetDataResponse other) : this() {
results_ = other.results_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public GetDataResponse Clone() {
return new GetDataResponse(this);
}
/// <summary>Field number for the "results" field.</summary>
public const int ResultsFieldNumber = 1;
private static readonly pb::FieldCodec<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> _repeated_results_codec
= pb::FieldCodec.ForMessage(10, global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair.Parser);
private readonly pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> results_ = new pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::RepeatedField<global::GrpcService.Protos.GetDataResponse.Types.KeyValuePair> Results {
get { return results_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as GetDataResponse);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(GetDataResponse other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if(!results_.Equals(other.results_)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= results_.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
results_.WriteTo(output, _repeated_results_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
results_.WriteTo(ref output, _repeated_results_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += results_.CalculateSize(_repeated_results_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(GetDataResponse other) {
if (other == null) {
return;
}
results_.Add(other.results_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
results_.AddEntriesFrom(input, _repeated_results_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
results_.AddEntriesFrom(ref input, _repeated_results_codec);
break;
}
}
}
}
#endif
#region Nested types
/// <summary>Container for nested types declared in the GetDataResponse message type.</summary>
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static partial class Types {
public sealed partial class KeyValuePair : pb::IMessage<KeyValuePair>
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
, pb::IBufferMessage
#endif
{
private static readonly pb::MessageParser<KeyValuePair> _parser = new pb::MessageParser<KeyValuePair>(() => new KeyValuePair());
private pb::UnknownFieldSet _unknownFields;
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pb::MessageParser<KeyValuePair> Parser { get { return _parser; } }
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public static pbr::MessageDescriptor Descriptor {
get { return global::GrpcService.Protos.GetDataResponse.Descriptor.NestedTypes[0]; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
pbr::MessageDescriptor pb::IMessage.Descriptor {
get { return Descriptor; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair() {
OnConstruction();
}
partial void OnConstruction();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair(KeyValuePair other) : this() {
pairs_ = other.pairs_.Clone();
_unknownFields = pb::UnknownFieldSet.Clone(other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public KeyValuePair Clone() {
return new KeyValuePair(this);
}
/// <summary>Field number for the "pairs" field.</summary>
public const int PairsFieldNumber = 1;
private static readonly pbc::MapField<string, string>.Codec _map_pairs_codec
= new pbc::MapField<string, string>.Codec(pb::FieldCodec.ForString(10, ""), pb::FieldCodec.ForString(18, ""), 10);
private readonly pbc::MapField<string, string> pairs_ = new pbc::MapField<string, string>();
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public pbc::MapField<string, string> Pairs {
get { return pairs_; }
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override bool Equals(object other) {
return Equals(other as KeyValuePair);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public bool Equals(KeyValuePair other) {
if (ReferenceEquals(other, null)) {
return false;
}
if (ReferenceEquals(other, this)) {
return true;
}
if (!Pairs.Equals(other.Pairs)) return false;
return Equals(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override int GetHashCode() {
int hash = 1;
hash ^= Pairs.GetHashCode();
if (_unknownFields != null) {
hash ^= _unknownFields.GetHashCode();
}
return hash;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public override string ToString() {
return pb::JsonFormatter.ToDiagnosticString(this);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void WriteTo(pb::CodedOutputStream output) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
output.WriteRawMessage(this);
#else
pairs_.WriteTo(output, _map_pairs_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(output);
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalWriteTo(ref pb::WriteContext output) {
pairs_.WriteTo(ref output, _map_pairs_codec);
if (_unknownFields != null) {
_unknownFields.WriteTo(ref output);
}
}
#endif
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public int CalculateSize() {
int size = 0;
size += pairs_.CalculateSize(_map_pairs_codec);
if (_unknownFields != null) {
size += _unknownFields.CalculateSize();
}
return size;
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(KeyValuePair other) {
if (other == null) {
return;
}
pairs_.Add(other.pairs_);
_unknownFields = pb::UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
}
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
public void MergeFrom(pb::CodedInputStream input) {
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
input.ReadRawMessage(this);
#else
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
break;
case 10: {
pairs_.AddEntriesFrom(input, _map_pairs_codec);
break;
}
}
}
#endif
}
#if !GOOGLE_PROTOBUF_REFSTRUCT_COMPATIBILITY_MODE
[global::System.Diagnostics.DebuggerNonUserCodeAttribute]
void pb::IBufferMessage.InternalMergeFrom(ref pb::ParseContext input) {
uint tag;
while ((tag = input.ReadTag()) != 0) {
switch(tag) {
default:
_unknownFields = pb::UnknownFieldSet.MergeFieldFrom(_unknownFields, ref input);
break;
case 10: {
pairs_.AddEntriesFrom(ref input, _map_pairs_codec);
break;
}
}
}
}
#endif
}
}
#endregion
}
In ASP.NET Core gRPC for WCF developers the Repeated fields for lists and arrays section explains that
repeated fields are represented by read-only properties of the Google.Protobuf.Collections.RepeatedField type rather than any of the built-in .NET collection types. This type implements all the standard .NET collection interfaces, such as IList and IEnumerable. So you can use LINQ queries or convert it to an array or a list easily.
You'll have to use Add/AddRange to add items to that property , eg:
var response=new GetDataResponse();
response.AddRange(results);
return response;
You don't need to wrap response in a Task to return it because your method has the async signature, so it already wraps return values. In any case, await Task.FromResult(x) just returns x

How to get associated name of linked resources in HAL

I am creating an API for project tasks. It has a TasksController as listed below. I am generating hypermedia using WebApi.Hal and the service supports hal+json and hal+xml media types also.
Following is the response I currently have for the GET request http://localhost:51910/api/tasks/1. In the response there is a list of links for priorities – but they don’t have associated name in the response (to show in the UI – like Low, Medium, High, etc.).
What is the best HAL approach for getting name of the priorities also, using WebApi.HAL?
Note: The list of priorities can be enhanced in the future.
Priority
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
Controller
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
HAL Generation Related Classes
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Links.Add(LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID }));
}
}
}
HAL Specification mentions title - this will meet the requirement.
Following is the updated response.
{
"TaskID": 1,
"TaskName": "Task1",
"CurrentPriority": "Medium",
"Category": "IT",
"_links": {
"self": {
"href": "/api/tasks/1"
},
"priorities": [
{
"href": "/api/tasks/1/priorities/101",
"title": "Low"
},
{
"href": "/api/tasks/1/priorities/103",
"title": "High"
},
{
"href": "/api/tasks/1/priorities/104",
"title": "Critical"
}
]
}
}
WebAPI.HAL changes
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
Code
public static class LinkTemplates
{
public static class TaskLinks
{
public static Link TaskEntry { get { return new Link("self", "~/api/tasks/{taskID}"); } }
//public static Link PriorityLink { get { return new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}"); } }
public static Link PriorityLink
{
get
{
Link l = new Link("priorities", "~/api/tasks/{taskID}/priorities/{priorityID}");
return l;
}
}
}
}
public class TasksController : ApiController
{
// GET api/values/5
[HttpGet]
public TaskRepresentation Get(int id)
{
Task selectedTask = TasksHelper.GetTask(id);
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
//PUT For Setting Priority
[HttpPut]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public TaskRepresentation PutSetPriority(int taskID, int priorityID)
{
Task selectedTask = TasksHelper.GetTask(taskID);
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
//Update Task
if (selectedPriority != null)
{
selectedTask.CurrentPriority = selectedPriority.PriorityName;
}
else
{
throw new Exception("Not available");
}
TaskRepresentation taskRepresentation = new TaskRepresentation(selectedTask);
return taskRepresentation;
}
[HttpGet]
[Route("api/tasks/{taskID}/priorities/{priorityID}")]
public Priority Get(int taskID, int priorityID)
{
Priority selectedPriority = null;
List<Priority> allPriorities = TasksPrioritiesHelper.GetAllPriorities();
foreach (Priority p in allPriorities)
{
if (p.PriorityID == priorityID)
{
selectedPriority = p;
}
}
return selectedPriority;
}
}
public class TaskRepresentation : Representation
{
Task theTask;
public int TaskID{get{return theTask.TaskID;}}
public string TaskName{get{return theTask.Name;}}
public string CurrentPriority{get{return theTask.CurrentPriority;}}
public string Category{get{return theTask.Category;}}
public TaskRepresentation(Task t)
{
theTask = t;
}
public override string Rel
{
get { return LinkTemplates.TaskLinks.TaskEntry.Rel; }
set { }
}
public override string Href
{
get { return LinkTemplates.TaskLinks.TaskEntry.CreateLink(new { taskID = theTask.TaskID }).Href; }
set { }
}
protected override void CreateHypermedia()
{
foreach (Priority p in theTask.PossiblePriorities)
{
Link lnk = LinkTemplates.TaskLinks.PriorityLink.CreateLink(new { taskID = theTask.TaskID, priorityID = p.PriorityID });
lnk.Title = p.PriorityName;
Links.Add(lnk);
}
}
}
public class Task
{
public string Name { get; set; }
public int TaskID { get; set; }
public string Category { get; set; }
public string CurrentPriority { get; set; }
public List<Priority> PossiblePriorities { get; set; }
}
public class Priority
{
public int PriorityID { get; set; }
public string PriorityName { get; set; }
public string Revision { get; set; }
public DateTime ApprovalDate { get; set; }
}
public static class TasksPrioritiesHelper
{
public static List<Priority> GetAllPriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pMedium = new Priority { PriorityID = 102, PriorityName = "Medium" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
Priority pCritical = new Priority { PriorityID = 104, PriorityName = "Critical" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pMedium);
possiblePriorities.Add(pHigh);
possiblePriorities.Add(pCritical);
return possiblePriorities;
}
public static List<Priority> GetAdministrativePriorities()
{
List<Priority> possiblePriorities = new List<Priority>();
Priority pLow = new Priority { PriorityID = 101, PriorityName = "Low" };
Priority pHigh = new Priority { PriorityID = 103, PriorityName = "High" };
possiblePriorities.Add(pLow);
possiblePriorities.Add(pHigh);
return possiblePriorities;
}
public static List<Priority> GetPossiblePrioritiesForTask(Task t)
{
List<Priority> possibleTaskPriorities = new List<Priority>();
if (String.Equals(t.Category, "IT"))
{
possibleTaskPriorities = GetAllPriorities();
}
else
{
possibleTaskPriorities = GetAdministrativePriorities();
}
Priority currentTaskPriority = null;
foreach(Priority p in possibleTaskPriorities )
{
if(String.Equals(t.CurrentPriority,p.PriorityName ))
{
currentTaskPriority=p;
}
}
if(currentTaskPriority!=null)
{
possibleTaskPriorities.Remove(currentTaskPriority);
}
return possibleTaskPriorities;
}
}
public static class TasksHelper
{
public static Task GetTask(int id)
{
Task selectedTask = null;
List<Task> tasks = GetAllTasks();
foreach (Task t in tasks)
{
if(t.TaskID==id)
{
selectedTask = t;
}
}
return selectedTask;
}
public static List<Task> GetAllTasks()
{
List<Task> tasks;
tasks = new List<Task>();
Task t1 = new Task{Category = "IT",CurrentPriority = "Medium",Name = "Task1",TaskID = 1};
t1.PossiblePriorities = TasksPrioritiesHelper.GetPossiblePrioritiesForTask(t1);
tasks.Add(t1);
return tasks;
}
}

Equal Collection returns false when Object implements IEquatable?

I have the following test example:
var a = new List<OrderRule> {
new OrderRule("name", OrderDirection.Ascending),
new OrderRule("age", OrderDirection.Descending)
};
var b = new List<OrderRule> {
new OrderRule("name", OrderDirection.Ascending),
new OrderRule("age", OrderDirection.Descending)
};
var r = a.SequenceEqual(b);
Assert.Equal(a, b);
The variable r is true but Assert.Equal is false ...
The OrderRule class is the following:
public class OrderRule : IEquatable<OrderRule> {
public OrderDirection Direction { get; }
public String Property { get; }
public OrderRule(String property, OrderDirection direction) {
Direction = direction;
Property = property;
}
public Boolean Equals(OrderRule other) {
if (other == null)
return false;
return Property.Equals(other.Property) && Direction.Equals(other.Direction);
}
public override Boolean Equals(Object obj) {
if (ReferenceEquals(null, obj))
return false;
if (ReferenceEquals(this, obj))
return true;
if (obj.GetType() != GetType())
return false;
return Equals(obj as IncludeRule);
}
public override Int32 GetHashCode() {
return HashCode.Of(Property).And(Direction);
}
}
public enum OrderDirection { ASC, DESC }
Is there any problem with Assert.Equal when overriding Equals and implementing IEquatable?
UPDATE - HashCode helper
public struct HashCode {
private readonly Int32 Value;
private HashCode(Int32 value) {
Value = value;
}
public static implicit operator Int32(HashCode hashCode) {
return hashCode.Value;
}
public static HashCode Of<T>(T item) {
return new HashCode(GetHashCode(item));
}
public HashCode And<T>(T item) {
return new HashCode(CombineHashCodes(Value, GetHashCode(item)));
}
public HashCode AndEach<T>(IEnumerable<T> items) {
Int32 hashCode = items.Select(x => GetHashCode(x)).Aggregate((x, y) => CombineHashCodes(x, y));
return new HashCode(CombineHashCodes(Value, hashCode));
}
private static Int32 CombineHashCodes(Int32 x, Int32 y) {
unchecked {
return ((x << 5) + x) ^ y;
}
}
private static Int32 GetHashCode<T>(T item) {
return item == null ? 0 : item.GetHashCode();
}
}
Your code works as expected on my side. I've only fixed compilation erros - IncludeRule changed to OrderRule in Equals, also fixed OrderDirection enum members.

Sorting Nested ObservableCollection

In my WP7 project i'm using nested Observable collection. However, my problem is sorting this nested collection by with its nested collection in descending order.
Data Structure of Collection:
public class SubCategory : INotifyPropertyChanged
{
private string _catName;
public string CatName
{
get { return _catName; }
set
{
_catName = value; NotifyPropertyChanged("CatName");
}
}
private ObservableCollection<ToDoList> _lists;
public ObservableCollection<ToDoList> Lists
{
get { return _lists; }
set
{
if (_lists != value)
{
_lists = value;
NotifyPropertyChanged("lists");
}
}
}
And this is the nested collection
public class ToDoList : INotifyPropertyChanged//, INotifyPropertyChanging
{
#region NotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
#region NotifyPropertyChanging Members
// public event PropertyChangingEventHandler PropertyChanging;
/* private void NotifyPropertyChanging(string propertyName)
{
if (PropertyChanging != null)
PropertyChanging(this, new PropertyChangingEventArgs(propertyName));
}*/
#endregion
[Column(IsVersion = true)]
private Binary _version;
private int _ItemId;
[Column(IsPrimaryKey = true, IsDbGenerated = true, DbType = "INT NOT NULL Identity", CanBeNull = false, AutoSync = AutoSync.OnInsert)]
public int ItemId
{
get { return _ItemId; }
set
{
if (_ItemId != value)
{
//NotifyPropertyChanging("ItemdId");
_ItemId = value;
NotifyPropertyChanged("ItemId");
}
}
}
private string _ItemTitle;
[Column]
public string ItemTitle
{
get { return _ItemTitle; }
set
{
if (_ItemTitle != value)
{
//NotifyPropertyChanging("ItemTitle");
_ItemTitle = value;
NotifyPropertyChanged("ItemTitle");
}
}
}
private double _ItemLatitude;
[Column]
public double ItemLatitude
{
get { return _ItemLatitude; }
set
{
if (_ItemLatitude != value)
{
//NotifyPropertyChanging("ItemLatitude");
_ItemLatitude = value;
NotifyPropertyChanged("ItemLatitude");
}
}
}
private string _ItemAddress;
[Column]
public string ItemAddress
{
get { return _ItemAddress; }
set
{
if (_ItemAddress != value)
{
//NotifyPropertyChanging("ItemAddress");
_ItemAddress = value;
NotifyPropertyChanged("ItemAddress");
}
}
}
private double _ItemLongtitude;
[Column]
public double ItemLongtitude
{
get { return _ItemLongtitude; }
set
{
if (_ItemLongtitude != value)
{
//NotifyPropertyChanging("ItemLongtitude");
_ItemLongtitude = value;
NotifyPropertyChanged("ItemLongtitude");
}
}
}
private string _ItemDescription;
[Column]
public string ItemDescription
{
get { return _ItemDescription; }
set
{
if (_ItemDescription != value)
{
//NotifyPropertyChanging("ItemDescription");
_ItemDescription = value;
NotifyPropertyChanged("ItemDescription");
}
}
}
private bool isScheduled;
[Column]
public bool IsScheduled
{
get { return isScheduled; }
set
{
if (isScheduled != value)
{
//NotifyPropertyChanging("IsScheduled");
isScheduled = value;
NotifyPropertyChanged("IsScheduled");
}
}
}
private string _reminderId;
[Column]
public String ReminderId
{
get { return _reminderId; }
set
{
if (_reminderId != value)
{
//NotifyPropertyChanging("ReminderId");
_reminderId = value;
NotifyPropertyChanged("ReminderId");
}
}
}
private String _ItemTime;
[Column]
public String ItemTime
{
get { return _ItemTime; }
set
{
if (_ItemTime != value)
{
//NotifyPropertyChanging("ItemTime");
_ItemTime = value;
NotifyPropertyChanged("ItemTime");
}
}
}
private bool _isComplete;
[Column]
public bool IsComplete
{
get { return _isComplete; }
set
{
if (_isComplete != value)
{
//NotifyPropertyChanging("IsComplete");
_isComplete = value;
NotifyPropertyChanged("IsComplete");
}
}
}
private char _importance;
[Column]
public char Importance
{
get { return _importance; }
set
{
if (_importance != value)
{
//NotifyPropertyChanging("Importance");
_importance = value;
NotifyPropertyChanged("Importance");
}
}
}
[Column]
internal int _categoryId;
private EntityRef<Category> _category;
public Category ToDoCategory
{
get { return _category.Entity; }
set
{
//NotifyPropertyChanging("ToDoCategory");
_category.Entity = value;
if (value != null)
{
_categoryId = value.CategoryId;
}
//NotifyPropertyChanging("ToDoCategory");
}
}
}
I solved by changing the get method. Here is how i did.
public ObservableCollection<ToDoList> Lists
{
get
{
var l = from ToDoList lis in _lists
orderby lis.ItemId descending
select lis;
return new ObservableCollection<ToDoList>(l);
}
set
{
if (_lists != value)
{
_lists = value;
NotifyPropertyChanged("lists");
}
}
}

Why am I getting duplicated row inserts?

I have windows phone 7 application and classes for database mapping.
A Poll class looks like that:
[Table]
public class Poll // :BaseModel
{
//private int _pid;
//private string _pdesc;
//private bool _pisopen;
//private string _pname;
//private bool _prandom;
//private string _qlastupdticks;
//private string _ticks;
[Column(DbType = "INT NOT NULL IDENTITY(1,1)", IsPrimaryKey = true, IsDbGenerated = true)]
public int id { get; set; }
[Column(DbType = "INT")]
public int pid { get; set; }
//{
// get { return _pid; }
// set { SetValue(ref _pid, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column]
public string pdesc { get; set; }
//{
// get { return _pdesc; }
// set { SetValue(ref _pdesc, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column]
public bool pisopen { get; set; }
//{
// get { return _pisopen; }
// set { SetValue(ref _pisopen, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column]
public string pname { get; set; }
//{
// get { return _pname; }
// set { SetValue(ref _pname, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column]
public bool prandom { get; set; }
//{
// get { return _prandom; }
// set { SetValue(ref _prandom, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column(DbType = "NVARCHAR(255)")]
public string qlastupdticks { get; set; }
//{
// get { return _qlastupdticks; }
// set { SetValue(ref _qlastupdticks, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
[Column(DbType = "NVARCHAR(255)")]
public string ticks { get; set; }
//{
// get { return _ticks; }
// set { SetValue(ref _ticks, value, GetPropertyName(MethodBase.GetCurrentMethod())); }
//}
public override bool Equals(object obj)
{
var item = obj as Poll;
if (item != null)
{
Equals(item);
}
return false;
}
public bool Equals(Poll other)
{
if (ReferenceEquals(null, other)) return false;
return (other.pid == pid);
}
public override string ToString()
{
return string.Format("{0}_{1}", GetType().Name, pid);
}
public override int GetHashCode()
{
return ToString().ToUpper().GetHashCode();
}
}
Save method looks like that:
public bool RowsSave<T>(IEnumerable<T> entities, out string error)
{
error = string.Empty;
bool res;
var type = typeof (T);
using (var ctx = new PpaDataContext(_connectionString))
{
try
{
var entitesInDb = ctx.GetTable(type).Cast<T>().ToList();
var entitesForSave = new List<T>();
foreach (var entity in entities)
{
if (!entitesInDb.Contains(entity))
{
entitesForSave.Add(entity);
}
else
{
var index = entitesInDb.IndexOf(entity);
foreach (var prop in PropertiesGet(entity))
{
prop.SetValue(entitesInDb[index], prop.GetValue(entity, null), null);
}
}
}
if(entitesForSave.Count > 0)
{
ctx.GetTable(type).InsertAllOnSubmit(entitesForSave);
}
ctx.SubmitChanges();
res = true;
}
catch (Exception ex)
{
error = string.Format("{0}", ex.Message);
res = false;
}
}
return res;
}
When I try insert, each object inserts twice. What incorrect in this code?
The RowsSave method calling one time only.
This is a bit after the fact, but I've run into the exact same problem. This has to do with an error in overridden equality operators. In this specific case, the problem appears because the code does not return the value of the Equals function in:
public override bool Equals(object obj)
{
var item = obj as Poll;
if (item != null)
{
Equals(item);
}
return false;
}
That code will always return false. The corrected code should be:
public override bool Equals(object obj)
{
var item = obj as Poll;
if (item != null)
{
return Equals(item);
}
return false;
}
LINQ-to-SQL uses the object equals comparison after insertions. I'm not sure in what context and for what reason this happens, but if the comparison returns false, it runs the insertion again. If you're experiencing the same behavior, check any overridden equality methods for your entity for correctness.
I don't think you need the line:
ctx.SubmitChanges();
as an insert is being done on the line:
ctx.GetTable(type).InsertAllOnSubmit(entitesForSave);

Resources