CRUD with WPF, e.Row.Item and e.Row.DataContext are empty - wpf

I'm trying to build simplest CRUD application on Windows desktop.
Decided to go with WPF over Windows Forms and Lightswitch.
Created database, then generated "Code first from database" with Entity Framework.
Put datagrid with one table, set datasource. Run - it worked, I can Read.
Added a button, created Click handler with context.SaveChanges(); - ok, Update works.
Now, cannot get to Create part.
Added
authorsDataGrid_RowEditEnding(object sender, DataGridRowEditEndingEventArgs e)
{
if (e.EditAction == DataGridEditAction.Commit)
{
var newAuthor = e.Row.Item as authors;
context.authors.Add(newAuthor);
context.SaveChanges();
}
}
and unfortunately e.Row.Item (or e.Row.DataContext) comes in empty.
Where could be mistake?
WPF/WinForm CRUD tutorial links are welcome; been googling for days, haven't found a good one.

Ok, problem is solved; although original question is not answered, I went another way - created separate button which creates and adds Author based on currently selected item:
private void create_Click(object sender, RoutedEventArgs e)
{
var newAuthor = authorsDataGrid.SelectedItem as authors;
context.authors.Add(newAuthor);
context.SaveChanges();
this.authorsDataGrid.Items.Refresh();
}

Related

How do I refresh a tab control page after a database update

Using Visual Studio community 2017, winforms, C# and MySql DB.
I have a tab control page that displays the playlists created from the DB.
When I delete a playlists, it's removed from the DB, but is still visible in the tab page.
I created a button to try all refresh, update scenarios I could think of to no avail.
PlayListLoad() is my function that creates and populates my playlists.
Thanks for your help.
private void RefreshBtn_Click(object sender, EventArgs e)
{
PlayListLoad();
tabPage3.Update();
tabPage3.Refresh();
}
Found the answer through a lot of searches and try/error.
I just needed to clear the controls before updating.
private void RefreshBtn_Click(object sender, EventArgs e)
{
tabPage3.Controls.Clear();
PlayListLoad();
tabPage3.Update();
tabPage3.Refresh();
}

Webbrowser Control - overtyping does not delete selected text when editing HTML [duplicate]

In my C# app I get an xml from a server that contains some replies like in a forum thread (with elements like author, time, body, title, whatever).
When I get this xml, I create a new form in which i want to display these replies, and a little text box with an "add reply" button. I'd also like some edit buttons on perhaps my own replies in the reply list displayed in the form.
The simplest way that came to my mind to display the replies is to put a web browser control in the form, generate a full html page in a string from the xml, and throw it in that web browser control. And under it i can put the text box with the add reply button.
Everything is ok, except that i have no idea of how i could implement the edit function on my own replies (i mean i could add a link in there... but link to what)
I would like to know if there is a way to get that edit event from the web browser control (my guess is i can't) or another (maybe simple/easy) idea of displaying the replies in a winform using other controls
Yes, that's possible, you want to turn "design mode" on for the document. Add a reference to Microsoft.mshtml. Start a new Windows Forms project and drop a WB and a button on the form. Make the code look similar to this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
webBrowser1.DocumentText = "<html><body><textarea rows='15' cols='92' name='post-text' id='wmd-input'></textarea></body></html>";
webBrowser1.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser1_DocumentCompleted);
button1.Click += button1_Click;
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
mshtml.IHTMLDocument2 doc = webBrowser1.ActiveXInstance as mshtml.IHTMLDocument2;
doc.designMode = "On";
}
private void button1_Click(object sender, EventArgs e) {
var html = webBrowser1.Document.Body.All["post-text"].InnerHtml;
// do something with that
//...
}
}

WinForms Dialog Form -- Close or Dispose?

I've inherited some code and wanted to run this modification by you all, my concern is memory management.
Let us say I have a "base" Form with a bunch of buttons that open "dialog" forms. What is the recommended pattern for opening the dialog forms? Currently we display the "dialog" form like so (in the "base" Form code, upon button click):
ChangePasswordForm frm = new ChangePasswordForm();
frm.ShowDialog();
Then close it like so (in the "dialog" form code):
private void bCancel_Click(object sender, EventArgs e)
{
this.Close();
//this.Dispose(); <-- this is what I am considering adding.
}
My rationale for adding Dispose is that I am worried if this form is displayed and closed many times that each time a new instance of the form is created and its resources are never really released -- is this correct? Also, if the form has the "close" X in the top right, should I put a Dispose() call in the FormClosed event as well?
Thanks in advance.
I would use a using statement:
using (var frm = new ChangePasswordForm()) {
frm.ShowDialog();
}
Combine this with a DialogResult:
private void bCancel_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
}
Setting the DialogResult, will close the Dialog, and the caller/owner has some feedback.
And you don't have to worry about Close or Dispose.
According to MSDN you need to dispose under two conditions:
The two conditions when a form is not disposed on Close is when (1) it is part of a multiple-document interface (MDI) application, and the form is not visible; and (2) you have displayed the form using ShowDialog. In these cases, you will need to call Dispose manually to mark all of the form's controls for garbage collection.
MSDN Form.Close
Declaring the form in a using statement would be the appropriate way to handle this.
using (ChangePasswordForm frm = new ChangePasswordForm())
{
frm.ShowDialog();
}

Why is DragDrop not working under VS2010?

I have a winforms app that uses a UserControl. The user control's job is to collect a file that the user drops on it from Windows Explorer, Open the file, determine the type and handle it accordingly.
This control worked PERFECTLY under Visual Studio 2008 Pro. I upgraded to VS 2010 Pro, and now, it doesn't work. Is there a flag or a property that has changed that I should be aware of??
I made a quick demo to test. This demo works perfectly under 2008, but doesn't work at all under 2010.
The setup: Create a new winform project. Add a user control. Set the following code in the user control's code section. (compile to get the user control to appear in the toolbox) Add the user control to the form. Run the program, and drag ANY file from windows onto the form. If it works, the user control area should change colors.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
this.AllowDrop = true;
this.DragDrop += new DragEventHandler(UserControl1_DragDrop);
this.DragEnter += new DragEventHandler(UserControl1_DragEnter);
this.DragLeave += new EventHandler(UserControl1_DragLeave);
}
void UserControl1_DragLeave(object sender, EventArgs e)
{
this.BackColor = Color.FromName("Control");
}
void UserControl1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
this.BackColor = Color.Blue;
}
else
{
e.Effect = DragDropEffects.None;
}
}
void UserControl1_DragDrop(object sender, DragEventArgs e)
{
this.BackColor = Color.Yellow;
}
}
I'm open to any explanation or fix that you guys may think up!
UPDATE:
I tested using the comments listed below. STILL doesn't work. However, I have noted that it only fails while in the development environment. When I go to the bin directory and launch the program manually, it works fine. It just doesn't work when I am in the development environment, which makes debugging a bit difficult. Still looking for the big-picture fix.
A likely failure cause here is UIPI, the user interface component of UAC. You cannot drag from a non-elevated process and drop to a window owned by an elevated process. You'll trigger this when you started Visual Studio from a shortcut that has the "Run this program as an administrator" option in the Compatibility tab turned on. The only workaround is to turn that option off. Or to run it directly from the .exe file, as you discovered.

WPF ComboBox DropDown part appears in the wrong place

I put several ComboBoxes on a XAML window. When I expand any of them, the DropDown part appears on the upper left corner of the screen.
I use Visual Studio 2008 C# Express. I don't remember this phenomenon when I used Visual Studio 2008 (Trial Version), though I use the same FrameWork (3.5).
It seems to be a bug.
Workaround:
Use Window.Show() instead with a custom logic to simulate the ShowDialog() behavior.
This appears to be a bug in WPF. In my case, I was trying to open a window in the Loaded event of another window. To get around this, I set a timer up to fire, then used a delegate to open the window (cannot open the window in a timer event because the calling thread that opens a window must be STA).
Edit - timer isn't necessary - didn't see the answer above just queue it on the dispatcher...
private delegate void DelegateOpenWindow();
private DelegateOpenWindow m_DelegateOpenWindow;
private Timer loginTimer = new Timer(200);
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
// create delegate used for asynchronous call
m_DelegateOpenWindow= new DelegateOpenWindow(this.OpenWindow);
// start a timer to fire off the open window.
loginTimer.Elapsed += loginTimer_Elapsed;
loginTimer.Enabled = true;
}
void loginTimer_Elapsed(object sender, ElapsedEventArgs e)
{
loginTimer.Enabled = false;
this.Dispatcher.BeginInvoke(m_DelegateOpenWindow);
}
void OpenWindow()
{
MyWindow w = new MyWindow();
w.Owner = this;
w.ShowDialog();
}
I started observing this (and other strange behavioral quirks) yesterday when I tried to "tweak" window sizes, shapes, colors, and invoke a log-on dialog from the Window.Loaded event handler. I had been doing this just fine in each of a dozen+ individual "MVVM" pattern apps. Yesterday, I decided to move this from each app's code behind into a consolidated code-behind base class, since the pre-processing had become common in all those apps. When I did, the drop-downs in two ComboBoxes in the log-in dialog suddenly appeared in the upper left corner of my screen. I seem to have "solved" it by using the following technique (your mileage may vary):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
/*----------------------------------------------------------------------
* Do we have a View Model? If so, perform standard VM Initialization...
*---------------------------------------------------------------------*/
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}
WindowBaseLoadedHandler is the Loaded event handler. LoginDlg is a WPF app with a dialog containing two ComboBoxes.
Recap: After I consolidated the code into the Loaded event handler of the base class the ComboBox's drop down lists appeared in the upper left corner of my screen. Once I wrapped the logic into the Dispatcher.BeginInvoke call, the appropriate ComboBox behavior returned with lists below the current item.
I suspect WPF needs the application to return from the Loaded event to complete the layout system's initialization. That doesn't fully explain why it worked before, but I'll have to queue up my desire to hunt that "why" down for some rainy day in the future and celebrate overcoming the latest obstacle for today.
In any event, I hope someone finds this of use.
I'm using the latest .Net 4.5 and WPF framework and I still have this problem. One thing I noticed is that it only happen when there's an attached debugger. When the debugger is not attached, everything works fine.
I had the same problem on Visual Studio 2019.
Using window.Show() can help but it can ruin your design.
The solution is to open the window asynchronously.
var yourDialog= new YourDialog();
yourDialog.Owner = this;
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
this.Dispatcher.BeginInvoke(new Action(() =>
completion.SetResult(yourDialog.ShowDialog())));
bool? result = await completion.Task;
You can also create a more elegant solution by making the extension method:
public static class AsyncWindowExtension
{
public static Task<bool?> ShowDialogAsync(this Window self)
{
if (self == null) throw new ArgumentNullException("self");
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
self.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(self.ShowDialog())));
return completion.Task;
}
}
And you can use it like this:
await dlgReview.ShowDialogAsync();
It’s a bug in WPF (not the only one, I'm afraid). It happened when I opened another window in the Loaded Event, something like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Window selectionWindow = new SelectionWindow();
bool? result = selectionWindow.ShowDialog();
if (result == true)
RecordChanged();
}
I already found a workabout.

Resources