MacBook, defective by design banner

title:
Put the knife down and take a green herb, dude.


descrip:

One feller's views on the state of everyday computer science & its application (and now, OTHER STUFF) who isn't rich enough to shell out for www.myfreakinfirst-andlast-name.com

Using 89% of the same design the blog had in 2001.

FOR ENTERTAINMENT PURPOSES ONLY!!!
Back-up your data and, when you bike, always wear white.

As an Amazon Associate, I earn from qualifying purchases. Affiliate links in green.

x

MarkUpDown is the best Markdown editor for professionals on Windows 10.

It includes two-pane live preview, in-app uploads to imgur for image hosting, and MultiMarkdown table support.

Features you won't find anywhere else include...

You've wasted more than $15 of your time looking for a great Markdown editor.

Stop looking. MarkUpDown is the app you're looking for.

Learn more or head over to the 'Store now!

Monday, October 24, 2016

I'm close to releasing my second application to the Windows App Store, and have gotten just good enough at dealing with icons -- not a rocket scientist-level task by any stretch -- and thought I'd share.

Buy an icon

First, you need a square png (or other common format) of your icon that's at least 620x620 pixels. You can get a nice rounded image, but for the Windows Store, at least, a full square is better.

In my experience, it's not too difficult to trade a couple weeks of waiting (in case you get a bad contractor) and $5-$15 to get a servicable icon from fiverr.com. I've used folks from Pakistan each time, strangely enough, and gotten very good results three times, most recently with foxsquare. You do need to be respectful to some degree, as their contract says, "We Do NOT Take Order related to Pork, Nudity, Alcohol & Gambling." So far, so good for me.

Here's my latest, a design for a podcast feed creator. I wish the angles on the orange circles were perfectly symmetrical, and that the little "i" icon didn't reach the bottom of the image, but all things considered, this is a heck of a lot better than I could've done in several hours' work. It's a steal at $15 with .psd.

podcast feed icon

package.appmanifest

To insert the icon into your UWP app, open up your package.appmanifest file from Solution Explorer, and hit the Visual Assets tab.

appmanifest

Now you have a pretty simple interface to upload icon imagery. I recommend clicking on each of the lines from "Square 71x71 Logo" on down.

Resizing your original

For each one, you'll want to upload resized versions of your original icon. "But how do I get those resized images quickly?" you ask? That's easy if you download IrfanView, the handiest image viewer I've ever used.

Can't recall how many years I've used IrfanView now, and I was impressed to learn that it has extensive command line support.

First name the original square.png. Then run a bat file that resizes everything.

Here's the bat file I'm running, though you may have to change to the path where you have IrfanView installed:

"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(284,284) /aspectratio /resample /convert=.\284.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(600,600) /aspectratio /resample /convert=.\600.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(300,300) /aspectratio /resample /convert=.\300.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(620,620) /aspectratio /resample /convert=.\620.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(176,176) /aspectratio /resample /convert=.\176.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(200,200) /aspectratio /resample /convert=.\200.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(96,96) /aspectratio /resample /convert=.\96.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(88,88) /aspectratio /resample /convert=.\88.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(50,50) /aspectratio /resample /convert=.\50.png
"C:\Program Files (x86)\IrfanView\i_view32.exe" .\square.png /resize=(24,24) /aspectratio /resample /convert=.\24.png

pause

Boom. Done.

resized icons

Now go into the appmanifest UI and click on every largest size available for each asset line, then add your image.

NOTE: Some of these already have placeholder X images in your project. OVERWRITE THEM. You can overwrite in addition to the ones you're uploading to ensure you have decently high quality images.

how to upload icons and which to override

Rectangle splash and wide logos

This will leave you with just two assets unfilled, both rectangular. One is the "Wide 310x150" and the other the "Splash Screen" logo.

I kinda cop out here. I could probably get fiverr to make me some, but instead I open Ms. Paint.

The size we need is 1240x600. I tell Paint to create a new image, then I hit "resize" (Ctrl-W, strangely enough), and get it to 1240x600.

resizing in Paint

Make sure "Maintain aspect ratio" isn't checked.

Then I use the paint bucket to fill that all black. Finally, I paste in the 600x600 image IrfanView created and slowly move the middle pixel over until it's at 620 pixels into the image in Paint. Very high tech.

high tech centering success pants

Save it and put into both of the assets you had left.

Voila! The end. Cheap and quick.

Labels: , , , , , ,


posted by ruffin at 10/24/2016 12:12:00 PM
Thursday, October 20, 2016

From microsoft.com (via StackOverflow):

In order to be able to be instantiated as an object element, your class must meet the following requirements:

  • Your custom class must be public and support a default (parameterless) public constructor. (See following section for notes regarding structures.)

  • Your custom class must not be a nested class. Nested classes and the "dot" in their general CLR usage syntax interfere with other WPFย and/or XAML features such as attached properties.

[emphasis is mine]

That's got to be a joke, right? So I can't use a "nested class" (which would include anything with a java-style like com.yourCo.namespace) like this to create a ListView item template?

<ListView Grid.Row="1" Grid.RowSpan="1"
            Name="lstEps"
            IsItemClickEnabled="True">
    <ListView.ItemTemplate>


        <DataTemplate x:DataType="PodcastersFeed.Entities.EpCapsule"><!-- <<< No can haz namespace!! -->


            <Grid>
                <Border Background="LightGray" Height="30" Width="250">
                    <TextBlock
                        Text="{x:Bind Title}"
                        FontSize="18"
                        Foreground="Green"/>
                </Border>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Look, that's crazy-insane. I'd also had trouble with "namespaced" UserControls I'd created in the past, and lucked into figuring out they'd only work for me when I took them "out" of the non-local namespace, but figured I was doing something wrong. Maybe not.

Wow. I've made a wrapper class in my local namespace as a shuttle.

UWP unfortunately remains a hacky place.

Labels: , ,


posted by ruffin at 10/20/2016 04:03:00 PM
Friday, September 09, 2016

Oh, Pivots in UWP, you so crazy.

You may have heard that I'm writing a Markdown editor, MarkUpDown. It can have several files open at once, of course, and I'm using a UWP Pivot control to handle navigation.

As I got closer to releasing, it hit me that Ctrl-W, though common, isn't the most discoverable way to close those PivotItems. And now that I'm maintaining state between starts, so that whatever tabs you have open when you close the app are back on restart, closing each file "on purpose" is a lot more important than when they all closed on each restart.

That is, it looks like I need a UI for closeable tabs.

Not as easily said as done. You can customize the Header of the PivotItem pretty easily. In fact, a Header can be any object. You create a custom UserControl, throw in your favorite UI widgets, and you're golden.

In that UserControl, I put a TextArea and an icon of some sort, here a box with an X in it donated from Material Design Icons... Took a little experimenting to figure out exactly how to put text and an icon into the header presentably, though. I initially used a ViewBox, which seemed to scale the Path style image I'm using fairly well, no resizing necessary, but the ViewBox hated responding to clicks (or, in this case, "Taps" and "Presses"). Apparently you can manually set something called HandledEventsToo to make it catch events that are already caught by something with higher priority, but that strange Boolean reminds me of CSS' !important a little too much.

I replaced the ViewBox with a Button to be conventional, and then placed the Path style icon in there. I've got decent click event handling now, though it was difficult (well, at least "non-trivial") to get the icon to display centered. I went through the old process of using WPF Geometry Transformer to "Tansform" [sic] the Path into something smaller, and poof... -ish.

<PivotItem
    x:Class="CloseableTabs.CloseableTabHeader"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CloseableTabs"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400">

    <StackPanel Orientation="Horizontal">
        <TextBlock Margin="0,0,0,0" Name="txtHeader" FontSize="18">Test</TextBlock>
        <Button Background="White" Click="Button_Click">
            <Button.Content>
                <PathIcon Data="M13.3000001907349,2.09999990463257L3.5,2.09999990463257 2.51005053520203,2.51005053520203 2.09999990463257,3.5 2.09999990463257,13.3000001907349 2.51005053520203,14.2899494171143 3.5,14.6999998092651 13.3000001907349,14.6999998092651 14.2899494171143,14.2899494171143 14.6999998092651,13.3000001907349 14.6999998092651,3.5 14.2899494171143,2.51005053520203 13.3000001907349,2.09999990463257 M13.3000001907349,13.3000001907349L3.5,13.3000001907349 3.5,3.5 13.3000001907349,3.5 13.3000001907349,13.3000001907349 M11.8999996185303,5.87999963760376L9.3799991607666,8.39999961853027 11.8999996185303,10.9200000762939 10.9200000762939,11.8999996185303 8.39999961853027,9.3799991607666 5.87999963760376,11.8999996185303 4.90000009536743,10.9200000762939 7.42000007629395,8.39999961853027 4.90000009536743,5.87999963760376 5.87999963760376,4.90000009536743 8.39999961853027,7.42000007629395 10.9200000762939,4.90000009536743 11.8999996185303,5.87999963760376z" />
            </Button.Content>
        </Button>
    </StackPanel>
</PivotItem>

That's fun, isn't it?

example of two closeable tabs

That looks okay, but there are still two problems.

  1. How do I set the Label (now placed in txtHeader) of my UserControl in XAML?
  2. How I do I remove the PivotItem once its button is clicked.

Okay, three problems -- I really should change the icon to a greyed-out version when the PivotItem's not active. That looks awful. Mark that down for version two.

Accessing a property in custom XAML from C

I found the answer to the first pretty easily: You have to use a Dependency Property, of course!

Dependency property values are not stored as fields on the class, they are stored by the xaml framework, and are referenced using a key, which is retrieved when the property is registered with the Windows Runtime property system by calling the DependencyProperty.Register method.

But wait! There's more!

Defining a dependency property can be thought of as a set of concepts. These concepts are not necessarily procedural steps, because several concepts can be addressed in a single line of code in the implementation. This list gives just a quick overview. We'll explain each concept in more detail later in this topic, and we'll show you example code in several languages.

  • Register the property name with the property system (call Register), specifying an owner type and the type of the property value.
  • There's a required parameter for Register that expects property metadata. Specify null for this, or if you want property-changed behavior, or a metadata-based default value that can be restored by calling ClearValue, specify an instance of PropertyMetadata.
  • Define a DependencyProperty identifier as a public static readonly property member on the owner type.
  • Define a wrapper property, following the property accessor model that's used in the language you are implementing. The wrapper property name should match the name string that you used in Register. Implement the get and set accessors to connect the wrapper with the dependency property that it wraps, by calling GetValue and SetValue and passing your own property's identifier as a parameter.
  • (Optional) Place attributes such as ContentPropertyAttribute on the wrapper.

Note If you are defining a custom attached property, you generally omit the wrapper. Instead, you write a different style of accessor that a XAML processor can use. See Custom attached properties.

... [Oh, but there's more... -mfn] ...

In some scenarios, you are defining dependency properties for objects that are used on more than one UI thread. This might be the case if you are defining a data object that is used by multiple apps, or a control that you use in more than one app. You can enable the exchange of the object between different UI threads by providing a CreateDefaultValueCallback implementation rather than a default value instance, which is tied to the thread that registered the property.

Tis a silly place

I feel like the Knights of the Round Table after they've considered whether to go to Camelot. Okay, nevermind. 'Tis a silly place. I won't make these new headers XAML-friendly for "version mvp". We're going to set the Label somewhere outside of XAML. Moving on to #2...


Removing a PivotItem on custom UI click

My first bright idea, which I've used before, is to take the sender, cast to the appropriate widget, find its Parent, and just slowly climb my way back up the UI hierarchy until I find what I need. That is, I'll drill up, like a jQuery closest, until I have the PivotItem, then the Pivot, that I need. Then I can remove the PivotItem from the Pivot's Items collection. Easy, right? The best part is that this normally doesn't change, and you can have the PivotItem remove itself without any serious hooking in with what's around it. (I could probably do this more impressively with reflection, and essentially hook an extension method up for UIElement that parallels the jQuery closest method I references earlier.)

But crimminy. Here's the drill-up code I ended up with, originally in the UserControl's Button's Click event. Remember that this is just exploratory code at this point.

System.Diagnostics.Debug.WriteLine("Click");
Button btn = (Button)sender;
System.Diagnostics.Debug.WriteLine(btn.Parent.GetType());

var spam = (StackPanel)(btn.Parent);

var header = (CloseableTabHeader)(spam.Parent);
var headerItem = (PivotHeaderItem)(header.Parent);

PivotHeaderPanel headerPanel = (PivotHeaderPanel)(headerItem.Parent);
Grid weirdPiGrid = (Grid)headerPanel.Parent;

ContentControl contentControl = (ContentControl)weirdPiGrid.Parent;
Grid anotherGrid = (Grid)contentControl.Parent;
PivotPanel pivotPanel = (PivotPanel)anotherGrid.Parent;
ScrollViewer scrollViewer = (ScrollViewer)pivotPanel.Parent;
Grid yaGrid = (Grid)scrollViewer.Parent;
Grid yaGrid2 = (Grid)yaGrid.Parent;

That's interesting, right? Not only is it much more convoluted a design than I would've expected, we also never get a PivotItem or a Pivot -- yaGrid2 is the "root element" of the page, I think. And the stuff we do get, like PivotPanel, come with warnings like this:

PivotPanel isn't typically used for general XAML UI composition.

/sigh This was easy, wasn't it? My UI traversal has me lost in the funhouse rather than in a cleanly executed UI widget hierarchy that follows its own mental model. Feels like I went out of the back door and I'm seeing the outside of the house isn't finished quite yet. Unfortunately, I get the impression that UWP is held together by chicken wire and duct tape a lot more than I'm used to seeing in a Microsoft UI toolkit.

There's probably some easy way to save what I'm trying to do from the fire, but forget it. For version mvp, I'm changing the CloseableHeader constructor from this...

public CloseableTabHeader(string headerText) : base()
{
    this.InitializeComponent();
    txtHeader.Text = headerText;
}

... to this...

public PivotItem itemParent = null;
public Pivot pivotParent = null;

public CloseableTabHeader(string headerText, PivotItem itemParent, Pivot pivotParent) : base()
{
    this.InitializeComponent();
    txtHeader.Text = headerText;
    this.itemParent = itemParent;
    this.pivotParent = pivotParent;
}

I think you see where I'm going. Yes, I feel a little dirty too. Now I can remove it easily in the Button's Click event:

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (null != this.itemParent && null != this.pivotParent)
    {
        this.pivotParent.Items.Remove(this.itemParent);
    }
}

Hrm. Perhaps "parentPivot" is better than "pivotParent", and same with itemParent. In any event, you want to bubble up to the closest PivotItem and Pivot, and this makes that stupidly straightforward, though I do wonder how much Dispose-ing I should be doing.

I don't love that set-up, and I really dislike the way the buttons' bounds "highlight" simply when you mouse over the icon, like this:

highlighted close button

... but overall, that's a workable solution that will make discovery for tab closure much more straightforward for non-keyboard addicts.

Labels: , , ,


posted by ruffin at 9/09/2016 08:56:00 AM
Saturday, March 05, 2016

I'm testing WebView.InvokeScript in my UWP app, and think I've found my favorite test script...

Array.prototype.forEach.call(document.querySelectorAll("img"), 
    function (n) { n.src = "https://tafttest.com/200x200.png"; });

Here's the image that quick script puts into every img tag on the page.

insert alt text

This is from a service that produces any sized image of Taft you want, within reason. You just type in the dimensions you want (eg, https://tafttest.com/200x200.png), and up it comes.

It's like a gigantic hat. It's funny. Probably doesn't have to be Taft, but it's funny. Though not as funny as the one it'll give you if you grab a landscape...

insert alt text

insert alt text

I kind of like this one better, but I'm not sure of the copyright, unfortunately. ;^)

Array.prototype.forEach.call(document.querySelectorAll("img"), 
    function (n) { n.src = 
        "http://taftswag.weebly.com/uploads/6/0/6/4/60646335/3178534_orig.jpeg"; 
    });

swag

Again, funny.

swaggy T

Not funny? That a suggested further search is "Kittens with guns". What's wrong with the internet?

More about the Taft Test here.

Labels: ,


posted by ruffin at 3/05/2016 07:18:00 PM
Saturday, February 27, 2016

Well, that was fun. I went all the way around my elbow to get to my nose on UWP TextBox scrollbars. I figured out how to set it in XAML pretty quickly, but for some reason spaced on getting it working programmatically.

In XAML, things looked like this:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <TextBox
        AcceptsReturn="True"
        ScrollViewer.VerticalScrollBarVisibility="Auto"
        ScrollViewer.HorizontalScrollBarVisibility="Auto"
        Name="txt"></TextBox>
</Grid>

So naturally I thought I should be able to do something like this in code... (To be clear, the following doesn't work, though, in my defense, it apparently used to in Silverlight)

// ... where `this` is, obviously, the TextBox. We're in the constructor right now.
this.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
this.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;

Or, maybe, at worst, this:

this.ScrollBarVisibility.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
this.ScrollBarVisibility.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;

Nope, no dice at all.

Hey me, it turns out that's the wrong idiom, you idiot! After going all the way through putting the stupid TextBox into its own ScrollViewer, and then managing scrolling by coordinating SizeChanged events in the TextBox (wait, whaaa?), I stumbled onto this MSDN page, which I'm suspicious I'd found before, which had the secret incantation for UWP TextBoxen:

TL;DR -- Here's the answer...

ScrollViewer.SetVerticalScrollBarVisibility(this, ScrollBarVisibility.Auto);
ScrollViewer.SetHorizontalScrollBarVisibility(this, ScrollBarVisibility.Auto);

That's a weird idiom for me, though it's essentially the same thing you do when you set rows and columns for Grids...

TextBox txtMd = new TextBox();
Grid.SetRow(txtMd, 1);
Grid.SetRowSpan(txtMd, 2);
Grid.SetColumnSpan(txtMd, 1);
grid.Children.Add(txtMd);

I'd expect each SetRow and SetRowSpan to be methods on the individual grid instantiations rather than a static method on Grid proper.

And it's not like the start of the text on the MSDN page helped a ton... It starts by making you think you have to manage this all yourself. Maybe it changed later? Nah, I'm sure I missed the answer a half-inch below.

A multi-line TextBox will continue to grow vertically as text is entered unless itโ€™s constrained by its Height or MaxHeight property, or by a parent container. You should test that a multi-line TextBox doesnโ€™t grow beyond its visible area, and constrain its growth if it does.

Oh well. Live and learn. Man, I made that tougher than it shoulda been.

Labels: , , ,


posted by ruffin at 2/27/2016 02:49:00 PM
Friday, January 15, 2016

You can see them here.

Or in a giant image here (click the image for full-size):

Labels: , ,


posted by ruffin at 1/15/2016 10:40:00 AM

<< Older | Newer >>


Support freedom
All posts can be accessed here:


Just the last year o' posts:

URLs I want to remember:
* Atari 2600 programming on your Mac
* joel on software (tip pt)
* Professional links: resume, github, paltry StackOverflow * Regular Expression Introduction (copy)
* The hex editor whose name I forget
* JSONLint to pretty-ify JSON
* Using CommonDialog in VB 6 * Free zip utils
* git repo mapped drive setup * Regex Tester
* Read the bits about the zone * Find column in sql server db by name
* Giant ASCII Textifier in Stick Figures (in Ivrit) * Quick intro to Javascript
* Don't [over-]sweat "micro-optimization" * Parsing str's in VB6
* .ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture); (src) * Break on a Lenovo T430: Fn+Alt+B
email if ya gotta, RSS if ya wanna RSS, (?_?), ยข, & ? if you're keypadless


Powered by Blogger etree.org Curmudgeon Gamer badge
The postings on this site are [usually] my own and do not necessarily reflect the views of any employer, past or present, or other entity.