Tuesday, May 4, 2010
Context menus
So, I have a ton of database connections in VS2008, because they are all SQLite databases. I can right click on one and delete it. If I select more than one, the right click menu is gone. Why can't I select all my random DB files and delete the connections at once ? The DEL key also did not work, if there's a way to do it, I didn't see it.
Friday, April 30, 2010
Random properties in WPF UI Elements
So, in WPF, I have some tool windows showing. I want to only show one at a time. I want when I show one, to hide the others. And, when I show one, I want it to go to the last position it had. Seems simple enough. My windows are all borderless, so I have a button for dragging and I use the DragMove() method to make that all work. So, if you click the button within a certain timeframe, it toggles hide/show, otherwise it calls DragMove, which does the rest for you.
The issue is that DragMove allows you to move the window, but when you're done, it has the old Left/Top values. In other words, the values in the control are not tied to what they represent, they are free agents that sometimes get updated when the control moves, but not always. This reminds me of what I realised the 'Width' and 'Height' properties are provided for some sort of joke, and the ActualWidth and ActualHeight ones are needed ( because the Width is not the ActualWidth, right ? ). I suspect this has something to do with the half cocked move to respecting DPI settings, but I'm not sure, I just know I've never needed or found the Width or Height property to be worth anything.
So, I try to track the mouse to keep the values stored myself. Well, it turns out the the methods in WPF to get the mouse position do not work during a drag operation. So, the whole thing is useless. I needed to p/invoke GetCursorPos, then track for myself my left and top positions on the basis that WPF is incapable of doing so. It works nicely now. I should add, the Left and Top are settable, which is obvious ( so you can move a window ), but useful to me now, because I can tell it where it is, as it plainly does not know. And the fact my windows do not move at ALL when I lift my mouse is a good double check that the values I calculated are correct, unlike the ones WPF tracks.
The issue is that DragMove allows you to move the window, but when you're done, it has the old Left/Top values. In other words, the values in the control are not tied to what they represent, they are free agents that sometimes get updated when the control moves, but not always. This reminds me of what I realised the 'Width' and 'Height' properties are provided for some sort of joke, and the ActualWidth and ActualHeight ones are needed ( because the Width is not the ActualWidth, right ? ). I suspect this has something to do with the half cocked move to respecting DPI settings, but I'm not sure, I just know I've never needed or found the Width or Height property to be worth anything.
So, I try to track the mouse to keep the values stored myself. Well, it turns out the the methods in WPF to get the mouse position do not work during a drag operation. So, the whole thing is useless. I needed to p/invoke GetCursorPos, then track for myself my left and top positions on the basis that WPF is incapable of doing so. It works nicely now. I should add, the Left and Top are settable, which is obvious ( so you can move a window ), but useful to me now, because I can tell it where it is, as it plainly does not know. And the fact my windows do not move at ALL when I lift my mouse is a good double check that the values I calculated are correct, unlike the ones WPF tracks.
Friday, March 26, 2010
Owning a PrintDialog in WPF
The default settings when you create a new window in WPF make no sense at all. For starters, they all appear on the taskbar. Secondly, the ShowDialog method doesn't have an overload that takes the parent window as a parameter, nor does it default to Application.Current.MainWindow, so you end up with a ton of windows floating around that can pop behind each other, etc. However, it is typically easy to set the Owner of a window, set ShowInTaskbar to false, and then call ShowDialog. However, I have recently come across an issue in our software that at first glance was impossible to resolve.
We have our main application window, which shows image and video content. It's possible to show an image as full screen, and to do this, we create a new window, with no frame, make the main window it's owner, and show it to fill the screen area. In this window we have a print tool, which you can select, and then click on the form to print the image you can see. My issue was, when you click on the print dialog itself to select 'OK' or to change the printer, instead of it responding to your click, it disappears, and when you close the window, you find that it's floating above the main program window underneath. We did have one person work on this project who sometimes forgot to set the properties I mention above, and because the app fills the screen, we'd just not notice the item in the taskbar, nor would we notice that if someone were to click outside the dialog, it would disappear. But, there's something odd inside this control for it to disappear when I click *on* it. Nevertheless, I expected to set it's Owner and be done.
The PrintDialog control has no Owner property, no Parent property, nothing you can use to control the context in which it is shown. I simply had no options to tell it to stay visible when I click on it over a form that's not the main form of my app. How is this possible ? What complete lack of logical thought led to this situation ? I don't know.
The trick is that Application.Current.MainWindow is settable. This is the code I use to get around this bug in WPF - I set the MainWindow to be the window I am working in, and then set it back afterwards. I could perhaps put it in a try/catch, but I've never had this code throw any sort of error, so I've not done that. If it did throw an error, it would blow up the app, not change the main window and keep working, which would be my main possible cause for concern.
PrintDialog dlg = new PrintDialog();
// All of this is to get around the fact that WPF does not let us set a parent for the PrintDialog
Window currentMainWindow = Application.Current.MainWindow;
Application.Current.MainWindow = this;
if ((bool)dlg.ShowDialog().GetValueOrDefault())
{
Application.Current.MainWindow = currentMainWindow; // do it early enough if the 'if' is entered
PrintBitmapInternal(bitmap, dlg);
}
Application.Current.MainWindow = currentMainWindow; // in case the 'if' is not entered
One other thing, why does ShowDialog return a bool? ? Were they just so proud of themselves for coming up with nullable types ? This means I need to cast to bool in order to do a one line check, or I need to store the value to do two checks on it. Does it return null if the dialog is not shown ? Wouldn't an enum result in more easily read code ? Right now it's not clear to me when it could return null, except that I know it never has, in the years I have worked with WPF.
We have our main application window, which shows image and video content. It's possible to show an image as full screen, and to do this, we create a new window, with no frame, make the main window it's owner, and show it to fill the screen area. In this window we have a print tool, which you can select, and then click on the form to print the image you can see. My issue was, when you click on the print dialog itself to select 'OK' or to change the printer, instead of it responding to your click, it disappears, and when you close the window, you find that it's floating above the main program window underneath. We did have one person work on this project who sometimes forgot to set the properties I mention above, and because the app fills the screen, we'd just not notice the item in the taskbar, nor would we notice that if someone were to click outside the dialog, it would disappear. But, there's something odd inside this control for it to disappear when I click *on* it. Nevertheless, I expected to set it's Owner and be done.
The PrintDialog control has no Owner property, no Parent property, nothing you can use to control the context in which it is shown. I simply had no options to tell it to stay visible when I click on it over a form that's not the main form of my app. How is this possible ? What complete lack of logical thought led to this situation ? I don't know.
The trick is that Application.Current.MainWindow is settable. This is the code I use to get around this bug in WPF - I set the MainWindow to be the window I am working in, and then set it back afterwards. I could perhaps put it in a try/catch, but I've never had this code throw any sort of error, so I've not done that. If it did throw an error, it would blow up the app, not change the main window and keep working, which would be my main possible cause for concern.
PrintDialog dlg = new PrintDialog();
// All of this is to get around the fact that WPF does not let us set a parent for the PrintDialog
Window currentMainWindow = Application.Current.MainWindow;
Application.Current.MainWindow = this;
if ((bool)dlg.ShowDialog().GetValueOrDefault())
{
Application.Current.MainWindow = currentMainWindow; // do it early enough if the 'if' is entered
PrintBitmapInternal(bitmap, dlg);
}
Application.Current.MainWindow = currentMainWindow; // in case the 'if' is not entered
One other thing, why does ShowDialog return a bool? ? Were they just so proud of themselves for coming up with nullable types ? This means I need to cast to bool in order to do a one line check, or I need to store the value to do two checks on it. Does it return null if the dialog is not shown ? Wouldn't an enum result in more easily read code ? Right now it's not clear to me when it could return null, except that I know it never has, in the years I have worked with WPF.
Tuesday, March 16, 2010
Refactoring does not work
So, I wrote a method, with every intention of refactoring it to make it reusable at the end. Now I needed to change some stuff by hand because it passes the top level object in, if I have an object heirarchy. I don't mind that. However, because I had to change several values, it added a number of out parameters. The only issue with this is, all my values are only optionally modified. Therefore, the autogenerated code does not compile. The solution ? Just changing 'out' to 'ref'. Given that 'ref' code will compile where 'out' will not, why not just use 'ref' ?
Friday, March 12, 2010
Windows Explorer Integration
I love how when I go to save or open a file, I can right click and I've got access to all sorts of other stuff. But, try this. Open a Word file. Let's call it letter.doc. Now, click on 'Save As'. The dialog opens. Click on letter.doc and press F2. Rename it to Letter Old.Doc. Now, the text will still say Letter.Doc, but when you click the 'Save' button, it says 'The document Letter Old.Doc already exists'. So, if I click save, does the file get overwritten, or not ? One way or the other, it's a bug.
Thursday, March 11, 2010
Combo boxes in WPF
So, I want to give a user a list of PDFs that they can email, in a combo box to make it fit with some existing UI. The PDF data is in a class, so I bind the checkboxes in my template to a property, and it works in both directions. It's working well, that's a great feature in WPF. Except, when I click outside the text of my item, the item is selected, which is fine, but then I added code to set my property so it becomes checked. I've done this, but, no matter what I do, the checked item does not get checked in the actual list, so I open my combobox, and I have an item that is in my list, unchecked, but it's checked in the textbox. If I open the list, and check/uncheck the item in the list, the copy in the textbox stays in synch. It's just when I use code to check it, the UI does not catch up. Seems to me like a case where the two way binding just plain does not work - the same object is rendered in a combobox in two places, and in one place it does not render properly.
Did I mention that intellisense and the list of controls to add to a WPF form all do not work for me in visual studio, I suspect because of the bogus error message I get for every form in my project ?
The solution to this is the following code:
ComboBoxItem itm = PDFList.ItemContainerGenerator.ContainerFromItem(i) as ComboBoxItem;
ContentPresenter myContentPresenter = FindVisualChild(itm);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
CheckBox cb = myDataTemplate.FindName("chkSelect", myContentPresenter) as CheckBox;
if (cb != null)
cb.IsChecked = true;
Simple, right ? But you also need to add this method. You need to add a METHOD to give yourself the reusable ability to find a control inside a template in only 5 lines of code. Insane....
Here's that method
private childItem FindVisualChild(DependencyObject obj) where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child != null && child is childItem) return (childItem)child; else { childItem childOfChild = FindVisualChild(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Did I mention that intellisense and the list of controls to add to a WPF form all do not work for me in visual studio, I suspect because of the bogus error message I get for every form in my project ?
The solution to this is the following code:
ComboBoxItem itm = PDFList.ItemContainerGenerator.ContainerFromItem(i) as ComboBoxItem;
ContentPresenter myContentPresenter = FindVisualChild
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
CheckBox cb = myDataTemplate.FindName("chkSelect", myContentPresenter) as CheckBox;
if (cb != null)
cb.IsChecked = true;
Simple, right ? But you also need to add this method. You need to add a METHOD to give yourself the reusable ability to find a control inside a template in only 5 lines of code. Insane....
Here's that method
private childItem FindVisualChild
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) { DependencyObject child = VisualTreeHelper.GetChild(obj, i); if (child != null && child is childItem) return (childItem)child; else { childItem childOfChild = FindVisualChild
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Wednesday, March 10, 2010
Splitters and anchors
I am not sure if this issue comes back to the fact that I am using a splitter, because I can tell you that in the first instance, using a splitter in winforms is so counter-intuitive and convoluted that I had to look up an article online, and it gave me some code to use on the basis that they also felt that trying to add a splitter using the design view is an exercise in frustration and futility. The concept is simple, why is it so hard ?
So, I have my splitter. On one side is a listbox, on the other is a panel. On that panel I have two pictureboxes, which are supposed to be evenly spaced across the panel. No matter what I try with the anchor properties, I cannot get them to resize themselves so they keep their layout. If I make the first one anchor to the right and the left, it will fill the entire panel left to right, with the second one appearing on top of it. The second one does not resize at all, when I apply the same properties.
At least, I think that is true. If you click the property sheet for the Anchor property, a little box pops up. If you click what you want on that box and then hit build, when the app closes, you'll see an 'invalid property' message box and your changes will be lost, you need to explicity close that popup first. I believe I've done that and tested every combination I can think of, twice. I can't believe I'm writing a winforms app and resizing controls by hand.
**update
It seems that if it's in a splitter, the panel never fires a size changed event. I can catch the event on the main form, and then manually resize my controls, but I can't get the framework to position them for me. For anyone reading this, ignore the SizeChanged and ClientSizedChanged events ( and also the SplitterMoving event if you draw any sort of image or video inside your splitter ), the SplitterMoved event is the way to resize your form after the splitter has been moved.
So, I have my splitter. On one side is a listbox, on the other is a panel. On that panel I have two pictureboxes, which are supposed to be evenly spaced across the panel. No matter what I try with the anchor properties, I cannot get them to resize themselves so they keep their layout. If I make the first one anchor to the right and the left, it will fill the entire panel left to right, with the second one appearing on top of it. The second one does not resize at all, when I apply the same properties.
At least, I think that is true. If you click the property sheet for the Anchor property, a little box pops up. If you click what you want on that box and then hit build, when the app closes, you'll see an 'invalid property' message box and your changes will be lost, you need to explicity close that popup first. I believe I've done that and tested every combination I can think of, twice. I can't believe I'm writing a winforms app and resizing controls by hand.
**update
It seems that if it's in a splitter, the panel never fires a size changed event. I can catch the event on the main form, and then manually resize my controls, but I can't get the framework to position them for me. For anyone reading this, ignore the SizeChanged and ClientSizedChanged events ( and also the SplitterMoving event if you draw any sort of image or video inside your splitter ), the SplitterMoved event is the way to resize your form after the splitter has been moved.
Wednesday, March 3, 2010
More Weven hell
I have one other user ( my boss ) reporting that our program plays 15 out of 19 video thumbnails and plays them out of order. Now, this is different to the user who says it fails, or it works but with 19 out of order. The issue I have is, my code reads the files from a folder ( one line of code ), sorts them ( one line of code ), then assigns them as a datasource ( one line of code ). For this to fail, the list needs to lose it's sort order during the binding process, and the binding process needs to silently fail in mid stream. Of course, I cannot reproduce this. I am about to stress test my app by running an app at the same time that eats processor and HDD. So I wrote this app and copied it across on a memory stick, in a zip. I tried to use the unzip wizard, and I put my app inside program files, b.c I know there's all sorts of permissions issues I might hit otherwise.
The wizard tells me that it cannot create the folder and asks 'might it exist already ?'. Meaning, if it did, it would be an error, right ? So I try to create the folder myself to find out the error. Except after I gave admin permission it worked, and then the unzip wizard worked fine.
So, let's recap. Weven gave me an error and falsely told me what could have caused it. I created the exact situation that Weven told me would stop it from working, and then it worked. Anyone think they have this whole secure OS/permissions required thing worked out yet ?
The wizard tells me that it cannot create the folder and asks 'might it exist already ?'. Meaning, if it did, it would be an error, right ? So I try to create the folder myself to find out the error. Except after I gave admin permission it worked, and then the unzip wizard worked fine.
So, let's recap. Weven gave me an error and falsely told me what could have caused it. I created the exact situation that Weven told me would stop it from working, and then it worked. Anyone think they have this whole secure OS/permissions required thing worked out yet ?
Tuesday, February 9, 2010
Weven kills my app
So, I have a program which basically is just a video player. The main screen loads 19 small videos and plays them, you click one to play the whole thing in a bigger size. A client reported the videos are shown out of order ( this turned out not to be true ) and the app only runs once, and they have to reboot. Fact is, you need to start the app quickly when you boot, or it won't run. It gives a 'application is not responding' message, as far as I can tell, while some anti virus scans all the files. There ARE 19 of them, but they are VERY small. It seems to me that if windows is going to kill an application, it should do a better job of making sure the app is dead, instead of killing it.
Now, it IS true that my app works fine on Weven, so long as this anti virus is not present. But, it's not a great place to be in - 'my app works, but you have to remove your anti virus program'. I'm googling now for some way to tell Weven to give my app a bit more time to respond.
Now, it IS true that my app works fine on Weven, so long as this anti virus is not present. But, it's not a great place to be in - 'my app works, but you have to remove your anti virus program'. I'm googling now for some way to tell Weven to give my app a bit more time to respond.
Tuesday, February 2, 2010
Weven compatibility
I finally bought Weven, to test our new installer. One of our new features is that you can select a logo and text message to put on the header of our PDFs that are emailed and printed. The way I do this, is that I create a handouts folder in the app data section where our config data is stored, and I create each PDF when it's requested, if it's not already there. When the user changes the settings, I delete them all. This works fine in Vista.
On Weven, it was throwing an exception ( the code then just delivers the unmodified PDF ). I posted about this in an online forum and was surprised to find a number of people are reporting trouble accessing the app data area in Vista and Weven. In fact, one person told me they store all app data under My Documents now, because it's the only place they can trust to get access to.
I did some more digging and my PDF library was causing the exception, when I try to load a PDF in a subfolder of my application. I replaced that by inserting a call to File.ReadAllBytes, so that it used that overload. I assume the library (it's Syncfusion, FWIW, and I found the library in general to be excellent, well documented and easy to use), is asking for full write access when given a path, and does not provide an overload to ask for read access only.
So, I solved my issue, but now I'm worried.
1 - Other developers have abandoned the appdata areas altogether because of problems with access ( which I assume means that the shadow directory, which is it's own nightmare ( imagine support calls that the app won't remember preferences, for example ) is not reliable, either). So, am I playing with fire by assuming that just because MY setup of Vista and Weven work now, that it will work on all machines ? Yes, I've logged in as a guest and tested that, etc. but still.....
2 - The Syncfusion code works in Vista but not in Weven ( I always use a default OS install and assume that's what most users have ). That means that Weven is even more strict in what it allows. I can see why my code should not be able to just write to files in the program files area, but surely anything in my app folder or a sub folder should be excepted from that rule ? I guess it's not, and that's why we need to use the app data area, but why was it working in Vista then ?
Is it possible that the people reporting issues have just made some sort of mistake ? Perhaps, but these are people I've known for a long time, and who I trust, and I doubt they moved all their app data to my documents without some serious testing to prove they had an issue. As I can write to files in that area, I can only assume that some combinations of settings in Vista and Weven make that impossible. Given what a fiasco Vista was from the start, I can't help but start with Weven feeling a little cautious and concerned. I lost my MS MVP for being critical of Vista, yet I hear sales people in computer stores all the time selling Weven by telling people that Vista was a nightmare, and Weven has fixed the problems, so it seems problems with Vista were widespread. I do think Microsoft just flat out mishanded that ( and I only complained in public because, despite being an 'MVP', I was given no other channels in which to talk about my concerns, and when I did find channels for other issues ( like VS bugs ), I was always ignored anyhow.
Has anyone else had any new security issues from moving to Weven ? Anyone had issues with access to the app data area ?
On Weven, it was throwing an exception ( the code then just delivers the unmodified PDF ). I posted about this in an online forum and was surprised to find a number of people are reporting trouble accessing the app data area in Vista and Weven. In fact, one person told me they store all app data under My Documents now, because it's the only place they can trust to get access to.
I did some more digging and my PDF library was causing the exception, when I try to load a PDF in a subfolder of my application. I replaced that by inserting a call to File.ReadAllBytes, so that it used that overload. I assume the library (it's Syncfusion, FWIW, and I found the library in general to be excellent, well documented and easy to use), is asking for full write access when given a path, and does not provide an overload to ask for read access only.
So, I solved my issue, but now I'm worried.
1 - Other developers have abandoned the appdata areas altogether because of problems with access ( which I assume means that the shadow directory, which is it's own nightmare ( imagine support calls that the app won't remember preferences, for example ) is not reliable, either). So, am I playing with fire by assuming that just because MY setup of Vista and Weven work now, that it will work on all machines ? Yes, I've logged in as a guest and tested that, etc. but still.....
2 - The Syncfusion code works in Vista but not in Weven ( I always use a default OS install and assume that's what most users have ). That means that Weven is even more strict in what it allows. I can see why my code should not be able to just write to files in the program files area, but surely anything in my app folder or a sub folder should be excepted from that rule ? I guess it's not, and that's why we need to use the app data area, but why was it working in Vista then ?
Is it possible that the people reporting issues have just made some sort of mistake ? Perhaps, but these are people I've known for a long time, and who I trust, and I doubt they moved all their app data to my documents without some serious testing to prove they had an issue. As I can write to files in that area, I can only assume that some combinations of settings in Vista and Weven make that impossible. Given what a fiasco Vista was from the start, I can't help but start with Weven feeling a little cautious and concerned. I lost my MS MVP for being critical of Vista, yet I hear sales people in computer stores all the time selling Weven by telling people that Vista was a nightmare, and Weven has fixed the problems, so it seems problems with Vista were widespread. I do think Microsoft just flat out mishanded that ( and I only complained in public because, despite being an 'MVP', I was given no other channels in which to talk about my concerns, and when I did find channels for other issues ( like VS bugs ), I was always ignored anyhow.
Has anyone else had any new security issues from moving to Weven ? Anyone had issues with access to the app data area ?
Thursday, January 28, 2010
Plug and pray
Remember when plug and play was going to solve all of our driver issues ? Yeah, that was a good one, right ? What has me beat, I have a Microsoft webcam, a year or two old, not sure where the CD is, so I figure I'll ask windows to find the driver for me. It can't. Now, if I bought some dodgy Chinese made $10 camera, that would make sense to me. But if the functionality doesn't work for Microsoft hardware, how can it claim to work at all, and why does it even bother me every time I plug something in, when it's never in my life actually found and downloaded a driver for me ?
Saturday, January 23, 2010
Autosave
Does VS have any sort of autosave feature ? I'm not sure, but it should if it doesn't. I just added a window to my application. I got the usual message in the designer about not being able to parse a value into a DateTime. The only place my code uses any DateTime values, is in the Licensing, which is turned off by a macro in debug builds, and is not in any way called by anything that relates to the vanilla window I just created. I attached a second instance of VS to try to debug this message, but it doesn't catch it. So, if any of my code is causing this ( and it surely must be ), it is in a way far too esoteric and bizarre to be something that I could ever hope to debug and resolve. So, I spent an hour working on code, then I checked my mail, and got a debugger message that visual studio had crashed. All my work is lost. I guess I should hit save every few minutes, knowing how unstable Visual Studio is, but it's always a hard lesson to learn, that I expected it to be able to sit idle for a moment, and it just couldn't do it.
Tuesday, January 19, 2010
Intellisense
For reasons that I cannot understand, intellisense stops working frequently in VS for me. Now, I am not sure if how much it happens to me nowadays has to do with how quickly the VS designer breaks. My WPF project, which does no work with date times, anywhere, rarely will show a preview of my XAML, and if I get a meaningful error, it's 'cannot convert value to DateTime'. However, it's now starting to actually tell me that all the objects in my code behind do not exist, if they are defined in the XAML. So, I have to code blind, where usually I use prefixes like txt and lbl and then intellisense helps me find the control I want. Now, as I code, I am told that InitializeComponent does not exist, and my variables do not exist, either. Of course, when I do a build, it builds and runs fine.
Monday, January 18, 2010
Searching open documents in Visual Studio
Every now and again, I forget not to use an option that is fundamentally broken in a program. For example, just now, I decided to search 'Open Documents' in VS2008. I have two issues with this option. The first is that if I select it, all of the files that I have open are brought to the foreground as it searches, which both must slow things down a lot ( as surely rendering a screen of text is more work than scanning it for a word ) and leaves me with my documents all out of order from when I started. The second issue is, I just did a search for something that I knew was in an open document and no-where else. The find box, when I stopped the search, contained 10 matches. All the same line of code in the same file. I have 10 documents open, so I expect that means that it found the same match once for every document that it looked at, including the 9 that did not contain this text. One way or another, searching inside open documents only using visual studio is useless, and fundamentally broken. Who turned this code in ? Did someone write a use case that said this was what was supposed to happen ? I mean, I guess anything is possible....
Subscribe to:
Posts (Atom)