Because of the way data virtualization works (or doesn't) in WPF,
this was a whole lot different from WinForms. What I'm doing is
pretty simple, so I avoided the complexity (and quirks) inherent
to more complete data virtualization solutions. (All I really want
is to not render the entire thing up front.)
I looked at doing this in full WPF fashion, binding context object
properties to radio button IsChecked properties, but there's a lot
of conditional logic behind the scenes. I also wanted to do the
various formatted strings with a StringFormat binding, but that only
takes one argument, and some of them need two.
On the plus side, the format strings are now in Window.Resources,
rather than the global string table or the buttons themselves.
(The latter always felt a little sleazy, but it seemed like the
least annoying way to do it in WinForms.)
Also, add keyboard shortcuts to toolbar tooltips. This is particularly
useful for navigate forward/backward, as those aren't part of the
menu structure, and have two keyboard shortcuts apiece.
I'm planning to rework the dialog, so I didn't bother WPFing it up.
Also, explicitly recreate the contents of the Symbols window when
applying changes. This used to happen implicitly via
SymbolTableSubset and the "change serial" in SymbolTable, but that
approach doesn't make sense for a DataGrid.
The change in 779566 missed a step, so the TextChanged method wasn't
getting called. (When you bind TextBox Text to a string property, the
TextChanged events stop firing. You need to react to the property
"set" call instead.)
Also, enable UseKeepAliveHack. I have no reason to believe switching
to WPF will make remoting less flaky.
We can now Edit Long Comment and Edit Header Comment.
Changing the number of lines in a long comment exposed a bug in the
display list update. Fixed.
Running the WinForms version trashed the column widths, which exposed
the fact that the default column widths were set too narrow. Fixed.
On an unrelated note, hitting undo/redo quickly will sometimes leave
you scrolled to the bottom of the code list. Some sort of command-
handling race in the WPF framework? (Not fixed.)
The dialog is pretty straightforward. This is the first editor that
can cause a partial update -- if you edit a label, only the lines
that refer to that label are regenerated -- so I added the code for
partial display list updates as well.
Also, while working on this I noticed that long comments were getting
ellipsized at a bad place. The column width for the semi-hidden
column used for notes and long comments wasn't getting set. After
fiddling with it a bit I determined that it really needed to be set to
the sum of the widths of the rightmost four columns, and updated
whenever column sizes change. This was easier to do than I expected.
I may actually be getting the hang of WPF.
I haven't figured out how to make the AppendText(text, color) extension
work right with the WPF version of RichTextBox, but I was able to work
around the issue, and it's not really worth sinking time into.
The order of items in XAML was tied to enum values, which isn't
great. Since the value gets stored in the settings file, we want
the values to come from the code-behind. So now we provide an
ItemsSource for the combo box from the code-behind instead of
defining the items in XAML.
Took another swing at doing things WPF-style. Ended up with TextBox
objects backed by integer fields, which worked pretty well but
didn't get the min/max values. Set up validation instead, once I
figured out how to make it update in real time.
Relatively straightforward, thanks to the way WPF ComboBoxes work.
Spent some time fiddling with the column width text boxes, but
ended up with essentially the WinForms approach.
Notable items include the column show/hide buttons, which were
straightforward except for the "determine the default width" part,
and the font picker, which is no longer a standard dialog. The
latter was complicated by the absence of a good way to detect
whether a font is mono-spaced or not without calling back into code
meant for WinForms font manipulation (with a dash of PInvoke).
Yay WPF.
Also, enabled character ellipsis for code list items.
Added the progress dialog as a relatively generic thing (it was
implemented as a pair of dialogs in the WinForms version, for no
very good reason). Generation and assembler execution works.
Instead of traversing a single dual-element stack, use separate
stacks for forward and backward.
Record whether the jump was from a Note, so we select the right
set of lines when we return to it.
If nothing is selected, push the current top position on, instead
of doing nothing at all.
Correctly handle the case where somebody is trying to jump to the
current position.
These just needed to have methods added to the command definitions.
Also, added a style to the toolbar buttons so they fade when not
enabled.
Also, fixed the DataFileLoadIssue dialog, which was seriously broken.
I was setting the window size and letting the contents fill to fit.
Now I'm setting the content size and letting the window size itself
to fit around it. The latter feels like it'll hold up better as
things change.
Getting the layout just right got a little wordy in XAML. There's
probably a way to make a Grid do what I want. This'll do for now.
Also, fixed the labels on the buttons in DiscardChanges, which were
reversed.
Now preserving column widths for the three DataGrids and the main
ListView. In theory the various grids would conveniently auto-size
to the content, but in practice that doesn't work well with
virtualization.
There is, of course, no simple "the width has changed" event
provided by the control. On the plus side, you can attach a
property-change event handler to pretty much anything, so once you
know the trick it's possible to make everything work. Yay WPF.
This change pulls in the settings file code, which is mostly
unchanged except when it comes to saving and restoring the window
location and size.
The old system has been replaced with a PInvoke-based version that
calls the underlying Win32 window placement code. This is more
likely to be correct when multiple displays are in use, and can
record the un-maximized size of a maximized window. It leaves a
nasty XML string embedded in the config file, but it's not really
meant to be human-readable anyway.
The sub-window dividers all work completely differently from the way
they did in WinForms, and some of the behavior is a bit obscure
(like noticing when a splitter moves due to keyboard input, and
setting the position in a way that doesn't break the auto-sizing).
Yay WPF.
Still need to preserve column widths.
This turns out to be really important. Otherwise the modal dialog
doesn't stay on top of the application's window stack, which can
make things awkward when ShowInTaskbar is set to false. The easiest
way to ensure this is getting done is to make it part of the
constructor arguments.
The code now passes the parent window in explicitly. WPF MessageBox
avoids this by calling UnsafeNativeMethods.GetActiveWindow(), but
that feels weird. We could assume Application.Current.MainWindow
is the parent, but that seems like it could go quietly and horribly
wrong.
Pretty simple dialog, but it took a while to figure out the best
way to deal with input validation. Works from the various menus as
well as double-clicking on .ORG and address column entries.
Also, moved some stuff around to places that made more sense.