Software Architect at Genzeon Corporation in Malvern, Pennsylvania, Microsoft .NET MVP, Husband, Dad and Geek.
35716 stories
·
21 followers

UWP Tip #24 - Get Started Building Windows UI XAML with XAML Studio

1 Share
XAML Studio was recently made available as a Microsoft Garage project without much fanfare. You may have heard of it if you're a regular viewer of the On .NET show on Channel 9. XAML Studio's creator, Michael Hawker, joined Jeremy Likness to discuss the project last week.

What Is XAML Studio

XAML Studio aims to provide Windows UI developers with a quick way to create and prototype XAML markup for Windows. If you miss old lightweight XAML editors like XamlPad, you should install XAML Studio today. These are a few of the features already available in this early version of the tool.
  • Live Preview
  • Live Binding
  • Binding Debugging
  • Data Context Editor
  • Auto-Save (with Restore)
  • IntelliSense
  • Documentation Toolbox with Links to MS Docs
  • Alignment Guides
  • Namespace Helpers

Getting Started

You can search for XAML Studio in the Microsoft Store and install it from there or use this handy link. When you open the app for the first time, you'll be greeted by a Welcome screen like this.



XAML Editor

If you have an existing WinUI XAML file you would like to try, you can use the Open File link. Let's get started today by clicking the New File link to create and start editing your first XAML file.




The new XAML file is a Windows Page containing a Grid with a 2-line TextBlock. Let's start slow and the Run text of each line a little bit to read "Get Started with XAML Studio on UWP Tips" and "Check out the live preview.". You'll notice that the live preview is exactly that... live. The text in the preview will refresh as you change it in the editor.

IntelliSense and Live Preview

Let's test out the IntelliSense by adding a couple more controls to the page. We'll switch out the Grid for a StackPanel with the default vertical orientation and add a Button and another TextBlock.



Settings

The IntelliSense is quite nice, but I think the default Live Preview refresh interval is a little fast. The bright pink error messages about invalid markup are distracting while working in the editor. You can either disable auto-compilation or edit the interval in the app's settings. The default interval is to compile after 0.8 seconds of inactivity in the editor. I updated mine to 2 seconds.




You should take some time to explore all of the XAML Studio settings as you're getting familiar with the app.

Documentation Toolbox

Something else you should explore is the Documentation Toolbox in the left panel.




Here you can view all of the WinUI XAML controls available to the editor, complete with little info icons that link to the Microsoft Docs online documentation. The control name and namespace appear in the list for each item. If you have controls that you frequently use, you can add them to your favorites so they always appear at the top of the list.

Data Binding

Want to add some dynamic content to your page without coding up your model, view model or connecting to a live data source? You can create a mocked up data source with some JSON data in the Data Source pane on the left.




For this prototype, I grabbed some sample JSON data from one of Adobe's sites. This data contains an array of donuts, each with its own array of batters and toppings and some other properties. It's a handy bit of small, yet semi-complex data.

From the Data Source pane, you can save your JSON, open other JSON data files, or connect to a Remote Data Context. Using a remote data context is as simple as entering a REST Url that returns valid JSON data. The returned data will populate your Data Source window and can be saved for later use.

Here is my XAML markup from the screenshot above with bindings added for the donut JSON data.

<StackPanel Padding="40" DataContext="{Binding}">
     <TextBlock Margin="8">
         <Run FontSize="24" Foreground="#FFFC5185">Get Started with XAML Studio on UWP Tips</Run><LineBreak/>
         <Run>Check out the live preview.</Run>
     </TextBlock>
    <Button Content="I Do Nothing" Margin="8"/>


    <ListView ItemsSource="{Binding}">
         <ListView.ItemTemplate>
             <DataTemplate>
                 <StackPanel Orientation="Horizontal">
                     <TextBlock Text="{Binding Path=id}" Margin="4"/>
                     <TextBlock Text="{Binding Path=type}" Margin="4"/>
                     <TextBlock Text="{Binding Path=name}" Margin="4"/>
                     <TextBlock Text="{Binding Path=rating}" Margin="4"/>
                 </StackPanel>
             </DataTemplate>
         </ListView.ItemTemplate>
     </ListView>
</StackPanel>

These binding expressions are all valid except for one. Want to quickly know which of your bindings is invalid? Switch to the Debug Bindings pane and turn on the Debug toggle.




After debug is enabled on bindings, a list of the binding expressions will display in the pane with a 'Successful' or 'NotBound' status next to the binding target. A timestamp of the last bound time will display with any bindings that have been successful. In addition, the binding expressions in the code editor will be highlighted to indicate their status, making it easier to navigate to the failed bindings.

In my case, I tried to bind to a "rating" property, which does not exist on the donut array items in the JSON data.

Next Steps

That's all we're going to explore in this intro to XAML Studio. Next time we'll dive a little deeper into remote bindings, bind some more complex controls, and see how easily we can take our prototype XAML over to a real UWP application in Visual Studio.

Go check out XAML Studio today and be sure to provide feedback to Michael on Twitter!

Happy XAMLing!

Read the whole story
alvinashcraft
17 minutes ago
reply
West Grove, PA
Share this story
Delete

Amazon and Microsoft diverge on approach to housing crisis in their home region

1 Share
Microsoft President Brad Smith announces a new $500 million affordable housing fund. (GeekWire Photo / Monica Nickelsburg)

As two of the world’s most valuable companies, Amazon and Microsoft have created mind-boggling wealth and economic vitality in the Seattle region. But around them, housing prices have skyrocketed and the number of people experiencing homelessness has spiked as the rising tide of the tech industry fails to lift all boats.

Now the two tech giants are taking on the housing crisis, but their approaches are as different as the companies themselves.

That’s one of the topics we discuss on the new episode of GeekWire’s Week in Geek Podcast.

We also delve into the story of Bill Gates standing in line for a hamburger and the Seattle Sounders dropping Xbox in favor of Zulily on their jerseys.

But the more substantive news this week was Microsoft’s announcement of a $500 million initiative in the hopes of correcting the Seattle region’s dysfunctional housing market. It’s a novel approach. Microsoft plans to invest $475 million in low- and middle-income housing developments at market rate returns or lower. Microsoft President Brad Smith said the returns will be re-invested into the program so that it is sustainable long term. The remaining $25 million will be donated to organizations tackling the region’s homelessness crisis.

In recent years, Amazon has targeted a different symptom of the housing crisis: homeless families. Amazon is building a permanent shelter for Mary’s Place, a non-profit that provides services to homeless women and families, on the company’s Seattle campus. Through its support of groups such as Mary’s Place and FareStart, an organization that provides job training for people experiencing homelessness and poverty, Amazon has donated tens of millions of dollars.

Amazon CEO Jeff Bezos is also using some of his personal fortune on the issue. Last year he announced a new $2 billion philanthropic initiative called the Day One Fund. About $1 billion of the fund will be donated to homeless service providers.

There’s also a difference in optics between the two companies and their efforts to mitigate the housing crisis. Amazon was the poster child for an opposition effort to Seattle’s short-lived head tax, which would have collected funds from the city’s top-grossing companies to fund affordable housing. The tax was repealed quickly after passage because the Seattle City Council didn’t believe they could win a fight with the business community, including Amazon.

Here’s what Smith said when we asked him about the contrast between the companies.

GW: Lots of tech companies in the area have used their voice on this issue, but on some occasions, they’ve used their voice in ways that might seem a little bit incongruous. I’m thinking of the head tax and Amazon really loudly using their voice to say that they didn’t support it. So do you think that there’s dissonance between these things?

BS: I don’t know that there’s dissonance. I think we need to address the right problems, but we need to focus on the right solutions. I think it’s understandable that there were companies last summer in Seattle that thought that the solution that was being offered was going to be a step backwards rather than forwards. At the end of the day though, we all have to decide what we stand for and not just what we stand against, especially when we’re talking about a problem that affects our region as broadly and deeply as this one does. One of the benefits of being proactive is that it’s actually easier to fashion some ideas and hope to build some momentum behind them. That’s part of what we’re doing here. I do think that all of us in the tech sector in Puget Sound have an opportunity to take more steps to show the region what we stand for.

Microsoft stayed out of the head tax fight. fight. The company has also chosen to grow in the suburbs of Seattle, rather than the urban core. As a result, Microsoft hasn’t become the visible symbol of tech growth that Amazon has. Its foray into the housing issue comes off as more forward-looking than reactive.

Read the whole story
alvinashcraft
3 hours ago
reply
West Grove, PA
Share this story
Delete

One Dev Question - Is VSCode only good for JavaScript?

1 Share
From: Microsoft Developer
Duration: 01:39

In this One Dev Question series on Visual Studio Code, Chris Heilmann (@codepo8), Ramya Achutha Rao (@ramyanexus), Peng Lyu (@njukidreborn), and Daniel Imms (@Tyriar) answer questions about VS Code, a lightweight but powerful source code editor which runs on your desktop and is available for Windows, macOS and Linux. To learn more and to download VS Code, head to http://aka.ms/VSCode.

Read the whole story
alvinashcraft
3 hours ago
reply
West Grove, PA
Share this story
Delete

One Dev Question - What is the relationship between Visual Studio and Visual Studio Code?

1 Share
From: Microsoft Developer
Duration: 01:31

In this One Dev Question series on Visual Studio Code, Chris Heilmann (@codepo8), Ramya Achutha Rao (@ramyanexus), Peng Lyu (@njukidreborn), and Daniel Imms (@Tyriar) answer questions about VS Code, a lightweight but powerful source code editor which runs on your desktop and is available for Windows, macOS and Linux. To learn more and to download VS Code, head to http://aka.ms/VSCode.

Read the whole story
alvinashcraft
3 hours ago
reply
West Grove, PA
Share this story
Delete

SQL Server Data Migration: Tools and Services

1 Share

The Database Migration Team of the SQL Server Product Group has created the following tools and services to facilitate migration between different versions of SQL Server or between on-premises and SQL Azure DB in the cloud (but not only)!

Azure Database Migration Service (Azure DMS)

Designed as a seamless, end-to-end solution for moving on-premises SQL Server databases to the cloud.

https://aka.ms/AzureDMS

Database Migration Guide

Review all your options for an upgrade from on-premise SQL Server versions to Azure SQL Database.

https://aka.ms/datamigration

Azure Migrate

Easily discover, assess and migrate your on-premises virtual machine to Azure.

https://azure.microsoft.com/en-us/services/azure-migrate/

Azure Data Factory (ADF)

Create, schedule and manage your data integration at scale with our hybrid data integration (ETL) service.

https://aka.ms/adf

Data Migration Assistant (DMA)

Prepare your upgrade to a modern data platform by reviewing compatibility with your new SQL Server.

https://aka.ms/dma

SQL Server Migration Assistant (SSMA)

Automate database migrations to SQL Server from Microsoft Access, DB2, MySQL, Oracle, and SAP ASE.

https://aka.ms/get-ssma

Database Experimentation Assistant (DEA)

An A/B testing solution for changes in SQL Server environments, such as upgrades or new indexes.

https://aka.ms/dea-tool

SQL Server Data Tools (SSDT)

A modern development tool for SQL Server databases, Azure SQL databases, RS data models and IS packages.

https://docs.microsoft.com/en-us/sql/ssdt

Microsoft Data Migration Blog

The official team web log for Azure Data Magnet’s Database Migration Team

https://aka.ms/dm_blog 

 

If you are considering the migration to SQL Azure Database, I suggest you read this white paper: Choosing your database migration path to Azure.

For more information, you can follow the Data Migration Team YouTube channel, you will find videos and tutorials on SQL Server Data Migration Tools.

This opportunity is perfect to remind you that the next July 9, 2019 SQL Server 2008 and SQL Server 2008 R2 will exit from the maintenance program, Microsoft will not release updates on these two products, not even security updates. You can find all details here. This is the time to migrate!

You can also provide your feedback on Data Migration Tools and Services by writing to @Data_Migrations (datamigration at microsoft dot com).

Read the whole story
alvinashcraft
5 hours ago
reply
West Grove, PA
Share this story
Delete

Creating Solitaire in Flutter

1 Share

Making a Solitaire clone in Flutter (without a game engine)

After creating minesweeper in Flutter, we will now create another classic game in Flutter: Soltaire. Again, this uses no game engine and is pure Flutter code. If you already know how Solitaire works and are good at Flutter, skip to the end of the article for the Github link.

What is Solitaire?

Solitaire is a card game where the final objective is to enter all the cards into the four suit decks (top right decks) in order Ace -> King. At the beginning, we have seven columns of cards, all of which have one to seven cards respectively. The remaining cards are in a deck in the top left corner.

The card columns need to have cards in alternating colors (red,black) and need to be in order. We can drag one or multiple cards from one column to the other.

Fun fact: Solitaire was actually introduced in Windows to get people accustomed to new gestures like dragging with a mouse.

Getting Started

Our final aim is going to be this:

Let’s see the list of things we need to do:

  1. Create a basic card model
  2. Create 52 cards, split across columns randomly and put the rest back into the deck
  3. Creating a card widget
  4. Create a card column widget
  5. Create seven card columns
  6. Create four suit decks
  7. Create remaining cards deck

This article will be a bit more Flutter code heavy than the minesweeper article since here the logic is simpler but the components are slightly more complex.

Let’s code

We’ll start with the making a card.

Creating a basic card model

First let’s create a basic data model for the card.

A playing card has a suit (diamonds/hearts/spades/clubs) and a type (1,2,3,4…J,Q,K). Along with this we’ll add two other variables to store if this card is upside down and if this card has been opened before.

The model has three enums to store card type, suit and color. It also has a simple getter for getting the color of the card (red/black).

Create cards and randomly put them into card columns

First, we initialise all the lists that hold our cards.

// Stores the cards on the seven columns
List<PlayingCard> cardColumn1 = [];
List<PlayingCard> cardColumn2 = [];
List<PlayingCard> cardColumn3 = [];
List<PlayingCard> cardColumn4 = [];
List<PlayingCard> cardColumn5 = [];
List<PlayingCard> cardColumn6 = [];
List<PlayingCard> cardColumn7 = [];
// Stores the remaining card deck
List<PlayingCard> cardDeckClosed = [];
List<PlayingCard> cardDeckOpened = [];
// Stores the card in the final suit decks
List<PlayingCard> finalHeartsDeck = [];
List<PlayingCard> finalDiamondsDeck = [];
List<PlayingCard> finalSpadesDeck = [];
List<PlayingCard> finalClubsDeck = [];

(You can also make a List<List<PlayingCard>> here)

Now, we initialise all 52 cards:

List<PlayingCard> allCards = [];
// Add all cards to deck
CardSuit.values.forEach((suit) {
CardType.values.forEach((type) {
allCards.add(PlayingCard(
cardType: type,
cardSuit: suit,
faceUp: false,
));
});
});

Now, when the game starts, column 1 has 1 card, column 2 has 2 cards and so on. We have a total of seven columns. So we random 28 cards in total and add them to respective lists. We also need to open and flip the last cards in every column.

Random random = Random();
// Add cards to columns and remaining to deck
for (int i = 0; i < 28; i++) {
int randomNumber = random.nextInt(allCards.length);
  if (i == 0) {
PlayingCard card = allCards[randomNumber];
cardColumn1.add(
card
..opened = true
..faceUp = true,
);
allCards.removeAt(randomNumber);
} else if (i > 0 && i < 3) {
if (i == 2) {
PlayingCard card = allCards[randomNumber];
cardColumn2.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn2.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
} else if (i > 2 && i < 6) {
if (i == 5) {
PlayingCard card = allCards[randomNumber];
cardColumn3.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn3.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
} else if (i > 5 && i < 10) {
if (i == 9) {
PlayingCard card = allCards[randomNumber];
cardColumn4.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn4.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
} else if (i > 9 && i < 15) {
if (i == 14) {
PlayingCard card = allCards[randomNumber];
cardColumn5.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn5.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
} else if (i > 14 && i < 21) {
if (i == 20) {
PlayingCard card = allCards[randomNumber];
cardColumn6.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn6.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
} else {
if (i == 27) {
PlayingCard card = allCards[randomNumber];
cardColumn7.add(
card
..opened = true
..faceUp = true,
);
} else {
cardColumn7.add(allCards[randomNumber]);
}
allCards.removeAt(randomNumber);
}
}

Then we simply add the remaining cards in allCards to a remaining cards list. We also open the top card and add it to openedCards, which the user can drag into the card columns.

cardDeckClosed = allCards;
cardDeckOpened.add(
cardDeckClosed.removeLast()
..opened = true
..faceUp = true,
);
setState(() {});

Creating a card column

We’ll momentarily break out of order here and study the card column before we study the card widget itself.

A card column is a stack of cards with each card translated more in the Y direction than the last. If there was no translation, we would have all cards on top of each other.

A card column must also be able to accept other cards that are dragged to it. So, we need to use a DragTarget as well. If you are unfamiliar with Draggables and DragTargets, check out my deep dive on them here.

The parameters we accept are:

// List of cards in the stack
final List<PlayingCard> cards;

// Callback when card is added to the stack
final CardAcceptCallback onCardsAdded;

// The index of the list in the game
final int columnIndex;

onCardAdded is a callback to run a function when a card is dragged from one list to the other. columnIndex notes the index of the column in the seven columns we create. This is useful to note since we need the information of where a dragged card came from and went.

From the above information, can now conclude that this needs to be a Stack surrounded by a DragTarget :

DragTarget<Map>(
builder: (context, listOne, listTwo) {
return Stack(
children: widget.cards.map((card) {
int index = widget.cards.indexOf(card);
return TransformedCard(
playingCard: card,
transformIndex: index,
attachedCards: widget.cards.sublist(index, widget.cards.length),
columnIndex: widget.columnIndex,
);
}).toList(),
);
},
),

As we said, a CardColumn should be able to accept dragged cards, but only if they match the conditions of the game, namely, opposite color and in order. We encode the logic in the onWillAccept function of our DragTarget.

onWillAccept: (value) {
// If empty, accept
if (widget.cards.length == 0) {
return true;
}

// Get dragged cards list
List<PlayingCard> draggedCards = value["cards"];
PlayingCard firstCard = draggedCards.first;
if (firstCard.cardColor == CardColor.red) {
if (widget.cards.last.cardColor == CardColor.red) {
return false;
}

int lastColumnCardIndex = CardType.values.indexOf(widget.cards.last.cardType);
int firstDraggedCardIndex = CardType.values.indexOf(firstCard.cardType);

if(lastColumnCardIndex != firstDraggedCardIndex + 1) {
return false;
}

} else {
if (widget.cards.last.cardColor == CardColor.black) {
return false;
}

int lastColumnCardIndex = CardType.values.indexOf(widget.cards.last.cardType);
int firstDraggedCardIndex = CardType.values.indexOf(firstCard.cardType);

if(lastColumnCardIndex != firstDraggedCardIndex + 1) {
return false;
}

}
return true;
},

When a card is accepted, the callback is invoked. As we will soon see, with the cards dragged, we pass the data of the cards that were dragged as well as the column they came from.

onAccept: (value) {
widget.onCardsAdded(
value["cards"],
value["fromIndex"],
);
},

TransformedCard is the name of the card widget we will study next.

Creating a card widget

We need our card to:

  1. Take a PlayingCard model and display card accordingly
  2. Be draggable
  3. If dragged, carry all the cards below it with it as attached cards
  4. Translate in the Y axis depending on the position of the card in the card column (You can implement this behaviour in the card column but I’ve chosen to do it in the card itself).

In the parameters, we take:

// The card model to display
final
PlayingCard playingCard;
// The distance to translate the card in the Y axis (default: 15.0)
final double transformDistance;
// The index of the card in the card column
final int transformIndex;
// The index of the column in the seven card columns in the game.
final int columnIndex;
// Cards below the current card in the card column
final List<PlayingCard> attachedCards;

Like we discussed in the CardColumn section, we need to translate our cards in the Y direction based on their index in the list.

So first, we have a Transform widget as the outermost widget when building a card.

return Transform(
transform: Matrix4.identity()
..translate(
0.0,
widget.transformIndex * widget.transformDistance,
0.0,
),
child: _buildCard(),
);

Now we need to build the card itself, which has two cases:

  1. Card is facing down

If the card is facing downwards, we don’t need to make it draggable and we can just make a simple card back side.

Container(
height: 60.0,
width: 40.0,
decoration: BoxDecoration(
color: Colors.blue,
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(8.0),
),
)

2. Card is facing upward

This is the harder case. We need to:

  1. Display the playing card passed.
  2. Make it draggable (And attach all cards below the card if any).
  3. Attach all data so that another DragTarget can receive the card.

We need to make the outer widget a Draggable :

Draggable<Map>(
child: _buildFaceUpCard(),
feedback: CardColumn(
cards: widget.attachedCards,
),
childWhenDragging: _buildFaceUpCard(),
data: {
"cards": widget.attachedCards,
"fromIndex": widget.columnIndex,
},
);

feedback is the widget displayed when you drag the cards, which is another card column since if a card in the middle is dragged, then all cards below are also dragged along with it. So we construct a smaller CardColumn out of the card + the cards below it. (Yes, the CardColumn has cards which each have CardColumns as their feedbacks which each have cards. It’s like CardColumn-ception… without the Stack Overflow.)

Creating seven card columns

We simply use Expanded in a row for adding the card columns.

Create four suit decks

Since we can also drag cards to the suit decks, we need to use a DragTarget again, albeit with slightly different logic since the cards need to be accepted in the reverse order compared to the CardColumn .

// The suit of the deck
final
CardSuit cardSuit;
// The cards added to the deck
final
List<PlayingCard> cardsAdded;
// Callback when card is added
final
CardAcceptCallback onCardAdded;

We don’t need a deck of cards, we can simply show the topmost card. If it is empty, we construct an empty card.

Again, this is a DragTarget with a TransformedCard or an empty placeholder inside it.

However, the accept logic (onWillAccept) is different since here we accept a 2 after a 1, whereas in the CardColumn , we did the opposite.

Creating remaining cards deck

The remaining cards consist of two lists, remaining cards which are opened and remaining cards which are closed. We simply shift cards between two lists and show the topmost. We use an InkWell around the left card so that when the card is tapped, we move the top card from the closed list to the open list. The right card also needs to be draggable.

Handling card drags

Once a card or multiple cards are dragged from one CardColumn to the other, we need to add the cards to the list of card for that CardColumn and delete it from the other.

onCardsAdded: (cards, index) {
setState(() {
(newColumnName).addAll(cards);
int length = oldColumnName.length;
oldColumnName
.removeRange(length - cards.length, length);
_refreshList(index);
});
},

Handling win condition

After every drag, we simply check if the addition of the cards in the final suit decks is 52. If it is, we declare a win.

if (finalDiamondsDeck.length +
finalHeartsDeck.length +
finalClubsDeck.length +
finalSpadesDeck.length ==
52) {
_handleWin();
}

And finally, our result is:

For the complete code:

deven98/FlutterSolitaire

That’s it for this article! I hope you enjoyed it, and leave a few claps if you did. Follow me for more Flutter articles and comment for any feedback you might have about this article.

Some of my other articles:

Feel free to check out my other profiles as well:


Creating Solitaire in Flutter was originally published in Flutter Community on Medium, where people are continuing the conversation by highlighting and responding to this story.

Read the whole story
alvinashcraft
6 hours ago
reply
West Grove, PA
Share this story
Delete
Next Page of Stories