Keep connection always open for datatable twoway bind? - wpf

I'm working on a WPF project which includes update/delete/insert operation on many tables. For simplicity, I use a datagrid for each table. The users can operate on these tables directly. Once done, click a button, the tables in database get updated. Twoway bind is perfect in this case. Below code seems working fine.
However, one thing I do not like is: the _DBConnection is always open. It is closed until the form exists. Usually, I always open connection whenever I need to, use it, close it immediately.
So, my question is: is below code the correct way to do the twoway bind?
thanks
public partial class MainWindow : Window
{
private OleDbConnection _DBConnection;
private OleDbDataAdapter _DataAdapterAdmin;
private DataSet _DataSetAdmin;
public MainWindow()
{
InitializeComponent();
}
private void InitAdminGrid()
{
string cmd = "SELECT * FROM Admin ORDER BY LastName";
_DataAdapterAdmin = new OleDbDataAdapter(cmd, _DBConnection);
_DataSetAdmin = new DataSet();
_DataAdapterAdmin.Fill(_DataSetAdmin);
dgAdministration.BeginInit();
dgAdministration.DataContext = _DataSetAdmin.Tables[0];
dgAdministration.Items.Refresh();
dgAdministration.EndInit();
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
string connectionString = clsDataAccess.GetConnectionString();
_DBConnection = new OleDbConnection(connectionString);
_DBConnection.Open();
InitAdminGrid();
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
try
{
OleDbCommandBuilder cmd = new OleDbCommandBuilder(_DataAdapterAdmin);
_DataAdapterAdmin.Update(_DataSetAdmin);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Exception", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void MainWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (_DBConnection != null)
{
_DBConnection.Close();
_DBConnection.Dispose();
}
}
}

Related

Why does WPFMediaKit VideoCaptureElement created by code land ever in MediaFailed?

I add a VideoCaptureElement to a window in runtime but when I run this code it fires MediaFailed. But if I add the same element in XAML then it works fine, I can see the video from the laptop camera.
Am I doing anything wrong? Please help!
public partial class MainWindow : Window
{
WPFMediaKit.DirectShow.Controls.VideoCaptureElement VCE;
public MainWindow()
{
InitializeComponent();
VCE = new WPFMediaKit.DirectShow.Controls.VideoCaptureElement();
Content = VCE;
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
VCE.MediaOpened += VCE_MediaOpened;
VCE.MediaFailed += VCE_MediaFailed;
VCE.VideoCaptureDevice = WPFMediaKit.DirectShow.Controls.MultimediaUtil.VideoInputDevices[0]; // This is my laptop webcam
}
void VCE_MediaOpened(Object sender, RoutedEventArgs e) { ... }
void VCE_MediaFailed(object sender, WPFMediaKit.DirectShow.MediaPlayers.MediaFailedEventArgs e) { ... }
}
I had a similar problem with a MediaUriElement working in XAML but not working when instantiated in code-behind.
The solution for me was to Init the control:
VCE.BeginInit();
VCE.EndInit();
This would fit between instantiating (VCE = new...) and assigning (Content = VCE). I haven't tested your particular scenario, but it sounds like the same cause - there must be some extra work done in Init that happens automatically when using XAML.

Dispose ReportViewer object

How to Dispose ReportViewer object safely if application closed unexpectedly
Public Shared rv As New Microsoft.Reporting.WinForms.ReportViewer
I guess you are talking about issue mentioned here.
As mentioned in the link, you need to manually Dispose() the reportViewer instance on form closing event.
private void frmMyForm_FormClosing(object sender, FormClosingEventArgs e)
{
if (rv != null && !rv.Disposing && !rv.IsDisposed)
{
rv.Dispose();
}
}
OR
Either calling reportViewer.LocalReport.ReleaseSandboxAppDomain() in form closing event:
private void frmMyForm_FormClosing(object sender, FormClosingEventArgs e)
{
rv.LocalReport.ReleaseSandboxAppDomain();
}

Working with ProgressBar and ComboBox

I'm in trouble with a Marquee ProgressBar. I need to execute a method (refreshList()) to get a List<string>. Then I assign this List to a ComboBox, so ComboBox refreshes with the new Items. As refreshList() take 3 or 4 sec, I wanted to run a Marquee ProgressBar. But I couldn't. ProgressBar is ok, but ComboBox doesn't load new Items.
My refreshList() method:
private void refreshList(List<string> list)
{
albumList.DataSource = null;
albumList.DataSource = list;
}
I have the following code, it works fine:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
refreshList(N.getList(folderPath));
}
}
But I added a ProgressBar and wrote this code:
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
bgWorker.WorkerReportsProgress = true;
bgWorker.RunWorkerAsync();
}
}
And I placed refreshList() in doWork() method:
private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
refreshList(N.getList(folderPath));
}
But unfortunately this isn't working. Can anybody help me solving this problem? Thanks in advance.
You can use the MarqueeAnimationSpeed and Value properties of the ProgressBar control to stop and start the Marquee. There's no need to use WorkerReportsProgress* as you aren't incrementing a normal progress bar - you just want to "spin" the Marquee.
You can do something like the following:
public Form1()
{
InitializeComponent();
//Stop the progress bar to begin with
progressBar1.MarqueeAnimationSpeed = 0;
//If you wire up the event handler in the Designer, then you don't need
//the following line of code (the designer adds it to InitializeComponent)
//backgroundWorker1.RunWorkerCompleted += backgroundWorker1_RunWorkerCompleted;
}
private void changeDirectoryToolStripMenuItem_Click(object sender, EventArgs e)
{
fbd.RootFolder = Environment.SpecialFolder.MyComputer;
folderPath = "";
if (fbd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
folderPath = fbd.SelectedPath;
//This line effectively starts the progress bar
progressBar1.MarqueeAnimationSpeed = 10;
bgWorker.RunWorkerAsync(); //Calls the DoWork event
}
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = N.getList(folderPath); //Technically this is the only work you need to do in the background
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//these two lines effectively stop the progress bar
progressBar1.Value = 0;
progressBar1.MarqueeAnimationSpeed = 0;
//Now update the list with the result from the work done on the background thread
RefreshList(e.Result as List<String>);
}
private void RefreshList(List<String> results)
{
albumList.DataSource = null; //You don't need this line but there is no real harm.
albumList.DataSource = list;
}
Remember to wire up the RunWorkerCompleted event to backgroundWorker1_RunWorkerCompleted via the Properties bar, Events section in the designer.
To begin with, we start the ProgressBar's animation by setting the MarqueeAnimationSpeed property to a non-zero positive number as part of your successful folder selection.
Then, after calling RunWorkerAsync, the code builds your list in the DoWork method, then assigns the result to the DoWorkEventArgs, which get passed to the RunWorkerCompleted event (which fires when DoWork is finished).
In the backgroundWorker1_RunWorkerCompleted method, we stop the progress bar (and set it's value to zero to effectively return it to it's original state), and then we pass the list to the refreshList method to databind it and populate the ComboBox.
Tested using VS2012, Windows Forms, .Net 4.0 (with a Thread.Sleep to emulate the time taken for N.getList)
*WorkerReportsProgress, and the associated ReportProgress method/event are used when you want to increment the progress bar - you can tell the GUI that you are 10% done, 20% done, 50% done etc etc.

Why is this getting random user IDs and not the current user?

Some developers in my company are having a problem with developing an in-house system. In the code snippet below, winID should be assigned the current system's user's ID. Instead, it's being assigned someone else's ID, apparently at random. Any suggestions?
public partial class _Default : System.Web.UI.Page
{
protected void Page_PreInit(object sender, EventArgs e)
{
Page.Theme = "MasterTheme1";
if (Session["UserName"] == null)
{
using (((WindowsIdentity)HttpContext.Current.User.Identity).Impersonate())
{
WindowsIdentity winID = System.Security.Principal.WindowsIdentity.GetCurrent();
Session["UserName"] = winID.Name;
}
}
Response.Redirect("MainDB_Login.aspx");
}
protected void Page_Load(object sender, EventArgs e)
//Snip
}
Possibly cacheing in place (browser, or on server)?

C# EventHandler Beautiful Code (How To?)

I admit, it is kind of tiny, but I am looking for better ways to do the following code blocks. They should be self explaining...
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = sender as ListBoxItem;
if (listBoxItem != null)
{
var clickObject = listBoxItem.DataContext as ClickObject;
if (clickObject != null)
{
clickObject.SingleClick();
}
}
}
Another ugly one:
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
var lB = sender as ListBox;
if (lB != null)
StatusBoxA.Text = "Elements selected" + lB.SelectedItems.Count;
}
Yeah, I know, its not near-death-urgent. But I do NOT like the (if != null). Any magic ideas to shorten it even more :-)
Btw, I found some nice info about a similar topic: Loops on Null Items
Nice to read...
I love good, clean code but in most cases, clean & elegant doesn't mean short and smart. Code brevity is good for competitions. Changing an "if not null" statement to a foreach might seem way cooler but it's harder for everyone else working in the project to understand what you are trying to accomplish. Believe me, even you won't remember it a few months later :P. Your code is just fine as it is!
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = sender as ListBoxItem;
if (listBoxItem == null) return;
var clickObject = listBoxItem.DataContext as ClickObject;
if (clickObject == null) return;
clickObject.SingleClick();
}
One-liner:
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
As<ListBox>(sender, (lB) => StatusBoxA.Text = "Elements selected" + lB.SelectedItems.Count);
}
or, nested:
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
As<ListBoxItem>(sender, (listBoxItem) => {
As<ClickObject>(listBoxItem.DataContext,
(clickObject) => clickObject.SingleClick());
};
}
using this static generic method (T is destination type, input is object to cast, code is a delegate (or lambda expression) to execute on success:
static void As<T>(object input, Action<T> code) where T : class
{
T foo = input as T;
if (foo != null)
code(foo);
}
Since you're using known events from the .NET framework (as opposed to a third party) and from the code it looks like you're only using those methods for specific classes (i.e. ListBoxItems and ListBoxes), there are a few things you know to be true:
sender will never be null
sender will always be a ListBoxItem, or ListBox, respectively
So why use the as operator? Just cast!
Then the first snippet becomes
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var listBoxItem = (ListBoxItem)sender;
var clickObject = (ClickObject)listBoxItem.DataContext;
clickObject.SingleClick();
}
Note this isn't true in the general case (you wouldn't do this if you were handling all PreviewMouseDown events in that one handler for all Control types), but for event handling code like this, especially in UI code, you can be as certain as you can be of anything, that sender will not be null and sender will be of the type you expect.
Maybe I am just being pedantic but why do you need to cast the sender if you are using the event within its host containers code.
Regardless of who made the change to a list, couldn't you just give your listbox a name and use that.
<ListBox x:Name="listbox1" />
private void listBox_SelectionChangedA(object sender, SelectionChangedEventArgs e)
{
StatusBoxA.Text = "Elements selected" + listbox1.SelectedItems.Count;
}
Or you could even achieve some of this using binding with no code behind.
This is supposed to be the same as the first one, reformatted a little:
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
ClickObject clickObject;
if (
((sender as ListBoxItem) != null) &&
((clickObject = ((ListBoxItem)sender).DataContext as ClickObject) != null)
)
{
clickObject.SingleClick();
}
}
You can add extensions methods to Form elements, which can then trigger the events:
public static void OnSelectionChanged(this ListBox b, Action<ListBox> a)
{
b.SelectedIndexChanged += (s,e) =>
{
if (s is ListBox)
a(s as ListBox);
};
}
Using the same idea as Utaal's solution, but as an extension method...
public static void As<TSource>(this object item, Action<TSource> action) where TSource : class
{
var cast = item as TSource;
if (cast != null)
action(cast);
}
private void listBoxItem_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
sender.As<ListBoxItem>(listBoxItem =>
listBoxItem.DataContext.As<ClickObject>(clickObject =>
clickObject.SingleClick()));
}

Resources