- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 150
private DataTable CreateMasterDataTable() { DataTable dtMaster = new DataTable("Master"); dtMaster.Columns.Add("Id", typeof(int)); dtMaster.Columns.Add("SomeText", typeof(string)); dtMaster.PrimaryKey = [ dtMaster.Columns["Id"] ]; return dtMaster; }Now detail DataTable:
private DataTable CreateDetailDataTable() { DataTable dtDetail = new DataTable("Detail"); dtDetail.Columns.Add("Id", typeof(int)); dtDetail.Columns.Add("MasterId", typeof(int)); dtDetail.Columns.Add("SomeText", typeof(string)); dtDetail.PrimaryKey = [ dtDetail.Columns["Id"] , dtDetail.Columns["MasterId"] ]; return dtDetail; }DataSet:
DataSet dsMasterDetail = new DataSet("MasterDetail"); dsMasterDetail.Tables.Add(CreateMasterDataTable()); dsMasterDetail.Tables.Add(CreateDetailDataTable());Relation and add relation to DataSet:
DataRelation relMasterDetail = new DataRelation("MasterDetailRelation" , dsMasterDetail.Tables["Master"].Columns["Id"] , dsMasterDetail.Tables["Detail"].Columns["MasterId"] ); dsMasterDetail.Relations.Add(relMasterDetail);Now, lets create BindingSource and attach it to DataSource of DataGridView:
var dsMasterDetail = CreateMasterDetailDataSet(); BindingSource bsMaster = new BindingSource { DataSource = dsMasterDetail, DataMember = "Master" }; dgvMaster.DataSource = bsMaster; BindingSource bsDetail = new BindingSource { DataSource = bsMaster, DataMember = "MasterDetailRelation" }; dgvDetail.DataSource = bsDetail;Here notice that DataSource of detail BindingSource I have attached master BindingSource, as DataMember name of relation:
BindingSource bsDetail = new BindingSource { DataSource = bsMaster, DataMember = "MasterDetailRelation" };Example download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 440
public class SimpleCommandViewModel: INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); private RelayCommand _sampleCommand; public SimpleCommandViewModel() { _sampleCommand = new RelayCommand(ExecuteSampleCommand); } public void ExecuteSampleCommand() => MessageBox.Show("Hello world"); public RelayCommand SampleCommand { get => _sampleCommand; set { if (_sampleCommand == value) { return; } _sampleCommand = value; OnPropertyChanged(); } } }Here notice:
new RelayCommand(ExecuteSampleCommand);That means that by default my button is enabled, in comparsion of Klaus Loeffelmann article:
new RelayCommand(ExecuteSampleCommand, CanExecuteSampleCommand);Where his button will enabled only if CanExecuteSampleCommand is set to true. Now, build it at least once. Then in Properties -> DataBindings -> Command -> add new Object DataSource -> choose SimpleCommandViewModel, after choose SampleCommand from dropdown list. In Form Load event add code:
private void Form1_Load(object sender, EventArgs e) { simpleCommandViewModelBindingSource.DataSource = new SimpleCommandViewModel(); }Example download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 4524
Natively WebAPI doesn't support binding of multiple POST parameters.Here I already gave two examples of WebAPI with multiple Post parameters. Now I will use similiar approach to send image plus additional data, like file and folder name. First don't forget in Program.cs to add Service:
builder.Services.AddMvc().AddNewtonsoftJson();Controller:
using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json.Linq; namespace UploadImageServer.Controllers; public class UploadImageController : Controller { [HttpPost] [Route("UploadImage")] public async Task<IActionResult> UploadImage([FromBody] JObject? data) { if (data is null) return BadRequest(new { message = "No image." }); string? base64Image = data["image"]?.ToString(); if (base64Image == null) return BadRequest(new { message = "No image." }); byte[] imageBytes = Convert.FromBase64String(base64Image); Directory.CreateDirectory(data["folderName"]?.ToString() ?? string.Empty); string imagePath = $"{data["folderName"]}\\{data["fileName"]}"; await System.IO.File.WriteAllBytesAsync(imagePath, imageBytes); return Ok(new { message = "Image uploaded successfully." }); } }Server download from here. --- Client:
using Newtonsoft.Json.Linq; using System.Net.Http.Headers; string imageUrl = "spring.jpg"; string base64Image = ConvertImageToBase64(imageUrl); var jsonData = new JObject { ["image"] = base64Image , ["fileName"] = "magnolia.jpg" , ["folderName"] = "spring" }; string jsonContent = jsonData.ToString(); using HttpClient client = new HttpClient(); StringContent content = new StringContent(jsonContent); content.Headers.ContentType = new MediaTypeHeaderValue("application/json"); HttpResponseMessage response = await client.PostAsync("https://localhost:7028/UploadImage", content); if (response.IsSuccessStatusCode) { Console.WriteLine("Image uploaded successfully!"); } else { Console.WriteLine("Failed to upload image. Status code: " + response.StatusCode); } static string ConvertImageToBase64(string imagePath) { byte[] imageBytes = File.ReadAllBytes(imagePath); return Convert.ToBase64String(imageBytes); }Client download from here.
- Details
- Written by: Stanko Milosev
- Category: C#
- Hits: 757
Log4NetLogger log4NetLogger = new Log4NetLogger(log); AsyncFtpClient client = new AsyncFtpClient(host, user, pass); client.ValidateCertificate += OnValidateCertificate; client.Logger = new FtpLogAdapter(log4NetLogger); await client.AutoConnect(); await client.UploadFile(fileName, "/public_html/kmlTestDelete/test.kml"); private void OnValidateCertificate(BaseFtpClient control, FtpSslValidationEventArgs e) { e.Accept = true; }The method OnValidateCertificate I am using to accept any certificate, this part of code I took from here Class Log4NetLogger looks like this:
using log4net; using Microsoft.Extensions.Logging; using ILogger = Microsoft.Extensions.Logging.ILogger; namespace FluentFTPasyncExample; public class Log4NetLogger : ILogger { private readonly ILog _log; public Log4NetLogger(ILog log) { _log = log; } public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter) { string message = $"{formatter(state, exception)} {exception}"; if (!string.IsNullOrEmpty(message)) { switch (logLevel) { case LogLevel.Critical: _log.Fatal(message); break; case LogLevel.Debug: case LogLevel.Trace: _log.Debug(message); break; case LogLevel.Error: _log.Error(message); break; case LogLevel.Information: _log.Info(message); break; case LogLevel.Warning: _log.Warn(message); break; default: _log.Warn($"Encountered unknown log level {logLevel}, writing out as Info."); _log.Info(message, exception); break; } } } public bool IsEnabled(LogLevel logLevel) { switch (logLevel) { case LogLevel.Critical: return _log.IsFatalEnabled; case LogLevel.Debug: case LogLevel.Trace: return _log.IsDebugEnabled; case LogLevel.Error: return _log.IsErrorEnabled; case LogLevel.Information: return _log.IsInfoEnabled; case LogLevel.Warning: return _log.IsWarnEnabled; default: throw new ArgumentOutOfRangeException(nameof(logLevel)); } } public IDisposable BeginScope<TState>(TState state) { return null!; } }Notice that I am injecting log4net in constructor. Example download from here.