Deploying WCF Service
February 8, 2011 Leave a comment
Deploying WCF to ASP.NET Development Server
Deploying WCF to IIS
Hosting a WCF Service by Using Windows ProcessActivation Service (with TCP)
February 8, 2011 Leave a comment
January 12, 2011 Leave a comment
In order to customize the layout of Visual Studio we will open a new project. Opening a new project makes all tool windows available.

Figure 1 New Project Menu Selection

Figure 2 New Project Dialog
| Note |
| The Target Framework Version ComboBox value defaults to the last selection made. When creating a new project, verify the desired Target Framework Version is selected. |
| Tip |
| While it is permissible to have spaces in the project name this practice discouraged. |
Visual Studio provides a feature rich and powerful development environment for developers to create a wide range of application types. Figure 3 below pictures a suggested layout for WPF and Silverlight application development.
Figure 3 Visual Studio Layout

Figure 4 Alternate Document Outline Position
| Tip |
| For developers new to WPF or Silverlight, the Document Outline is an invaluable tool for understanding the sometimes deeply nested control tree. The Document Outline tree view makes it very easy to navigate and select objects in your application. |
| Tip |
| Bookmarks are available in XAML files as well as code files. This feature makes it very easy to switch between files. |
Design view provides true WYSIWYG (What You See Is What You Get) application design experience. Developers use this view to layout their applications.

Figure 5 Design View
Design view provides a Zoom control in the upper left corner to allow the developer to zoom design view in and out. See Figure 5 above. At the bottom of the zoom control is a toggle button. This button toggles between, “Fit in view” and “100% zoom level.”
The Pan tool is available when the design view is displaying horizontal and or vertical scrollbars. When the designer has focus and you press the SPACE BAR, the mouse cursor will change to the hand cursor indicating that you can pan the design surface. Click and drag the design surface to reposition it.
The Pan tool will only allow movement of the design surface if the scrollbar for the direction of movement is visible. When both horizontal and vertical scrollbars are visible the design surface can be repositioned in all directions.
The root size mode button toggles between a Fixed Size root and an Auto Sized root. The root is the outmost control. In Figure 5 the root control or container is a Window.
When set to Fixed Size, the root container will have the same height and width at design time and run time.
When set to Auto Size, the root container will have a fixed design time height and width and but will auto size itself at run time. See the Auto Size UserControl root in Figure 6 below.

Figure 6 Auto Sized Root
| Note |
| The root sizing becomes very important when designing UserControls. Typically UserControls consume the available space given to them by their hosting control and auto sizing is desirable. However, at design time if the UserControl was auto sized and had no content, it would shrink to size 0, 0. Auto Size root allows the UserControl to have a design time height and width and but also have auto size behavior at run time. |
After building a solution, when you select another tab that has a XAML file and the designer is visible, you’ll see the below Information bar. Click the Information bar to reload design view.

Figure 7 Information Bar
| Note |
| The Information bar is only shown for XAML files that were not the active Visual Studio document when the solution was built. If the current document is the XAML file, that document will automatically be reloaded during the build process. |
After building the solution, attempting to use Design View when an error exists will cause the below Information bar to appear at the top of Design View. You need to correct the errors and this Information bar will disappear, making Design View usable again.

Figure 8 Information Bar
The Split View Bar gives the developer powerful tools for controlling and sizing the design and XAML views.

Figure 9 Split View Bar
XAML view provides a complete editing experience for XAML documents, that includes IntelliSense, auto-formatting, syntax highlighting, and tag navigation. When you edit XAML, Design view updates to reflect your changes.
To easily navigate through your XAML document, you can either select elements on the design surface or use Document Outline to change your selection.
Visual Studio 2010 supports Markup Extension IntelliSense. IntelliSense options will appear as a dropdown list after typing a “{” to begin an element. Navigate IntelliSense with the arrow keys and press tab to select a value.
XAML errors are marked in the XAML editor with a blue squiggle underline, which can be hovered over to produce a tooltip with error information. Those same errors are also listed in the Error List as in Figure 10 below.

Figure 10 XAML Editor Error
| Note |
| Notice the yellow bar to the left of the <Button tag in Figure 10 above. This indicates this line of XAML has changed since the last time the file was saved. If the bar was green, this would indicate this line of XAML was changed and saved since the file was opened. |
If you open a XAML file in full XAML view the Properties Window for selected objects will not be available. The Properties Window depends on Design View being loaded. If you switch to Design View and click the displayed link to reload the designer, you can then switch back to full XAML view and the Properties Window will display the selected object.

The Tag Navigator allows easy navigation of the current leaf of the XAML document.

Figure 11 Tag Navigator
The Properties Window provides rich property editing for the selected object’s properties.

Figure 12 Properties Window

Figure 13 Property Marker Content Menu
There are a number of configurable XAML text editor options that can be set using the Visual Studio Options dialog. To open the Options dialog, click the Tools menu and select Options. When the Options dialog is displayed find Text Editor in the left TreeView and expand it. Then expand XAML and finally expand Formatting and click on Spacing.

Figure 14 XAML Editor Options

Figure 15 Attribute Single Space Formatting

Figure 16 Attribute Multi-Line Formatting
Take a few minutes to change the above settings with the simple XAML document you have loaded. After making a settings change, use the Format Document command and reformat the XAML to view how the command changes your XAML document formatting.
Reopen the Options dialog and navigate to the XAML, Miscellaneous tab.
Figure 17 XAML Editor Options
If “Closing tags” is selected, when editing XAML and you enter the close tag for the element, a matching end element tag will automatically be inserted. In Figure 18 below, <Button> was typed, </Button> was automatically inserted by Visual Studio.

Figure 18 Close Tag
If “Attribute quotes” is selected, when editing XAML and you enter a property name, both the closing and ending double quote will automatically be inserted after the equals sign for you.
If “Closing braces for MarkupExtensions” is selected, when editing a property value in XAML and you type “{” a corresponding “}” will be inserted for you.
If “Commas to separate MarkupExtension parameters” is selected, when editing a MarkupExtension in XAML, pressing the SPACE BAR will automatically insert a comma for you. After typing FirstName, pressing the SPACE BAR causes a comma to be inserted, and the insertion point moved one space to the right of the comma.
![]()
Figure 19 MarkupExtension Comma Insertion
If “Always open documents in full XAML view” is selected, when a XAML document is opened, XAML view will consume the designer region. When using this feature keep in mind the limitations discussed in the above section, “Full XAML View Limitations.”
By default, in Visual Studio 2010, each time you build a WPF and Silverlight project, any types that derive from FrameworkElement or higher will be automatically added to the Toolbox. The types that are added are grouped into Toolbox tab by assembly. The purpose of this feature is to make it easy for developers to consume the UserControls and CustomControls they create on a form.
To you enable/disable this feature by checking or un-checking the CheckBox Automatically populate toolbox items in Figure 17 above. The red arrow points to this CheckBox.
January 12, 2011 Leave a comment
Assets: Klasorunde Styles.xaml adında ResourceDictionary (bu uygulamada kullanılan görsel styleler) bulunur.
Views: Varsayılan olarak Uygulamadaki sayfalar bulunur bu sayfalar Page sınıfı tipinde xaml dosyasıdır.
Normal silvelight uygulamsı template inde bulunmayan 2 referans navigation uygulamaya ekli olarak oluşturulmuştur. Bunlar:
System.Windows.Controls – Frame controlunu içerir bu control silverlight Page controllerinde gezinmeyi sağlar, kullanıcı isteğine yada programsal olarak bu gezinme yani navigation geçerli bir URI ye göre sağlanır.
Sytem.Windows.Controls.Navigation – UriMapper sınıfını içerir: İstenilen URI ler başka URI lere dönüştürmek için UriMapping nesne koleksiyonunu içerir. UriMapper nesnesi ve içerdiği UriMapping nesnesini Frame kontrolünün UriMapper propertiesine oluşturulan bu UriMapping dictionary nesneleri atanır.
MainPage.xaml dosyasına bakıllığında bu namespacelerin ilgili prefix ile eklenip bildirimi yapılmıştır. Navigation ve uriMapper adı verilen iki prefixe xaml parserın tanıyabilmesi için iki assembly eklenmiştir.
xmlns:navigation=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation”
xmlns:uriMapper=”clr-namespace:System.Windows.Navigation;assembly=System.Windows.Controls.Navigation”
Ve alt kodlara baktığımızda ilgili prefixlerde ilgili sınıflar çağrılmıştır.
<navigation:Frame x:Name=”ContentFrame” Style=”{StaticResource ContentFrameStyle}”
Source=”/Home” Navigated=”ContentFrame_Navigated” NavigationFailed=”ContentFrame_NavigationFailed”>
<navigation:Frame.UriMapper>
<uriMapper:UriMapper>
<uriMapper:UriMapping Uri=”" MappedUri=”/Views/Home.xaml”/>
<uriMapper:UriMapping Uri=”/{pageName}” MappedUri=”/Views/{pageName}.xaml”/>
</uriMapper:UriMapper>
</navigation:Frame.UriMapper>
</navigation:Frame>
UriMapper koleksiyon sınıfı ilgili prefixde belirtilmiştir ve aynı prefixde UriMapping koleksiyon nesneleri belli property değerleri alacak şekilde oluşturulmuştur. Dikkat edilirse Frame sınıf nesnesi için navigation prefixi belirtilmiş ve bu prefixde Frame için UriMapper tipindeki dependency property tanımlaması yapılmıştır. (Frame.UriMapper)
Yani: Navigasyonun sağlanması için Page haritalandırılması yapılmalı bu page Urilerini UriMapper koleksiyon sınıfı UriMapping tipinde propertyler ile tutuyor, bu property tipindeki nesne propertylerinede ilgili uriler belirtiliyor, oluşan bu UriMapper koleksiyon nesnesi Frame nesnesindeki dependency propertye atanıyor ve yapı sağlanmış oluyor.
Oluşturulan bu Frame ve UriMapping nesnelerinin propertylerine baktığımızda:
Frame:
Source : Frame in load anındaki varsayılan sayfa
Navigated : Bu bir event dır Framede navigasyon sağlandığında çalışacak event adı. Event içeriği
private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
{
foreach (UIElement child in LinksStackPanel.Children)
{
HyperlinkButton hb = child as HyperlinkButton;
if (hb != null && hb.NavigateUri != null)
{
if (hb.NavigateUri.ToString().Equals(e.Uri.ToString()))
{
VisualStateManager.GoToState(hb, “ActiveLink”, true);
}
else
{
VisualStateManager.GoToState(hb, “InactiveLink”, true);
}
}
}
NavigationFailed : Gezinmede yani navigasyonda bir hata olduğunda işleyecek event adı
private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
e.Handled = true;
ChildWindow errorWin = new ErrorWindow(e.Uri);
errorWin.Show();
}
UriMapper koleksiyonundaki UriMapping nesne propertyleri ise:
Uri ve MappedUri property değerleri görünmekte bunlar string değerlerdir Uri çağırlacak sayfayı MappedUri ise çağıralacak sayfanın tam yoluna dönüştürülmesi ile sağlanır. Mesela
<uriMapper:UriMapping Uri=”/{pageName}” MappedUri=”/Views/{pageName}.xaml”/>
Gibi urimapping tanımında Uri { } arasındaki bir sayfa adı olan çağrılarda gideceği uri (mappeduri) belli yolu istenilen sayfa adı ile tanımlanarak belirtilir. Burada pageName değişken adıdır.
<uriMapper:UriMapping Uri=”" MappedUri=”/Views/Home.xaml”/>
Örneğinde ise herhangi bir boş Uri olmadığı durumda gideceği yol belirtilir.
Buradaki cağrılacak uri değerleri için bir hyperlink butonunda aşağıdaki gibi belirlenir.
<HyperlinkButton x:Name=”Link1″
Style=”{StaticResource LinkStyle}”
NavigateUri=”/Home”
TargetName=”ContentFrame”
Content=”home”/>
Ve
<HyperlinkButton x:Name=”Link2″
Style=”{StaticResource LinkStyle}”
NavigateUri=”/About”
TargetName=”ContentFrame”
Content=”about”/>
Şeklinde NavigateUri propertye göre hangi link tıklanırsa ilgili Uri değeri UriMapper koleksiyonundanki UriMapping nesne özelliklerindeki Uri ye göre işaretlenir ve Navigate oluşacak Page çağrılır. /About bir pagename değişken değeri olarak alınır ve MappedUri ye ilgili yola işaretlenir. Aynı şekilde /Home da bir değişkenin değeridir ilgili koleksiyon nesnesi bu iki sayfa için: <uriMapper:UriMapping Uri=”/{pageName}” MappedUri=”/Views/{pageName}.xaml”/>
dir. Link özelliklerine bakarsak TargetName özelliğindede uygulamadaki x:Name ile belirtilmiş Frame nesne adımız atanmakta.
Bu uygulamaya yeni sayfalar ekleyebilir o sayfa içeriğini değiştirebilir bu sayfa için bir linkbutonu oluşturabilir yada kod ile çağırma işlemi yapabiliriz hatta querystring oluşturabilir başka sayfalarda querystring değerine göre istenilen işlemleri gerçekleştirebiriz. Bunun için:
UriMapping eşleşmesi yapılması için koleksiyona ilgili sayfayı eklemeliyiz, Sayfa.xaml page oluşturduktan sonra, main.xaml da.
<uriMapper:UriMapping Uri=”girilen {not}” MappedUri=”/Views/Sonuc.xaml?not={not}”/>
Eğerki bir hyperlink buttonun click metodunda Uri nesnesindeki uri stringi “girilen {not}” şeklinde not adında bir değişkenle oluştuğudan eşleşen bu UriMapping nesnesindeki MappedUri sayfası çağrılacak,
Linki oluşturacağımız sayfaya bir hyperlink butonu oluşturup click eventında navigate edilecek uri stringini oluşturalım.
<HyperlinkButton x:Name=”link” FontSize=”14″ Content=”QueryString –>” Click=”link_Click”/>
Event için
private void link_Click(object sender, RoutedEventArgs e)
{
this.NavigationService.Navigate(new Uri(string.Format(“girilen {0}”, 32), UriKind.Relative));
//32 nolu ogrenciye git!
}
Link butonu tıklandığında UriMappingden eşleşme yapılır ve ilgili sayfaya gidilir, gidilen sayfa için sayfa navigate olduğunda işleyecek metoda
<TextBlock x:Name=”sonuc” FontSize=”24″></TextBlock>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
sonuc.Text = this.NavigationContext.QueryString["not"];
}
İle querystring den değişken alınır ve sayfanın text kontrolünde yazdırılır.
Not: Hyperlinkbutton kontrolü özelliklerinden Tag ile hangi eğer hyperlink bir listedeki her bir eleman olarak ayarlanmışsa o elaman birer sınıf nesnesi ise ör Customer, ve hyperlinkbutton nesnesinde Tag özelliği Bu customer nesnesinin id si için Binding edilmişse,ilgili Tag ilgili id yi vede customer ismini yada diğer özelliklerini gösterecektir.
Frame Sınıf Metodları
GoBack() : Bir geri navigasyon sağlar tabiki varsa, yoksa hata fırlatır.
GoForward() : Bir ileri navigasyon sağlar. Yoksa hata fırlatılır.
Navigate() : UriMapper sınıfında eşleşen uri verilerek o sayfaya navigasyon sağlar.
private void Link4_Click(object sender, RoutedEventArgs e)
{
ContentFrame.Navigate(new Uri(“/About”, UriKind.Relative));
}
Bu Uri UriMapperda tanımlıydı:
<uriMapper:UriMapping Uri=”/{pageName}” MappedUri=”/Views/{pageName}.xaml”/>
Refresh() : Bu metod gösterilen sayfanın tekrar yüklenmesini sağlar. Dikkat edilirse Frame sınıfını MainPage.xamlda oluşturmuştuk ve bu metodlarıda bu cs de kodla çağırıyoruz.
StopLoading() : Bu metod sayfa henüz navigasyona uğramadığında (durduğunda NavigationStopped eventi çalışır) navigasyonu durdurmak için kullanır.
Frame Sınıf Propertyleri
CacheSize : Navigasyon oluştuğunda oluşan Page tekrardan oluşturulmaz bir cache de tutulur ve ordan alınır eğerki cache de ki sayfa sayısının sınırlamak istersek bu özelliği kullanırız, bu özelliği kullanmak için Page sınıfının NavigationCacheMode özelliğinin Enabled yapmalıyız, eğerki bu özelliği Required yaprsak sayfa CacheSize özelliğine bakmadan yani page sayısının hesaplamadan sayfalar oluşturulacaktır yani cache atılacaktır.
Şeklinde 10 olarak cache ayarlanır bununla birlikte hangi sayfanın cachelenmeden etkilenip etkilenmemesi sağlanır.
Şeklinde About.xaml a cache adete bakılmaksızın cachelenme oluşacaktır, bunun yanında disapled değer verilerekte cache yapılmaması sağlanır.
CanGoBack, CanGoForward : true false döndüren özelliktir framede navigasyon oluşan sayfadaki geriyada iler gidebilme durumunu döndürür.
CurrentSource: Mevcut sayfanın Uri bilgisini elde etmek yada atamak için kullanılır
Frame Sınıfı Eventları
Gördükki sayfalar Frame sınıfı contentleri ve olaylar Frame tarafından kontrol ediliyor o halde devam edelim. Frame sınıfı eventlarıda contentlere yönelik olmakta.
FrameNavigation : Bu eventa content navigasyonu oluştuğunda gerekli işlemler yaptırılır.
Navigated : Bu event ile content (herhangi sayfa) oluştuğunda çalışacak işlemler belirtilir. Mesela
private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
{
foreach (UIElement child in LinksStackPanel.Children)
{
HyperlinkButton hb = child as HyperlinkButton;
if (hb != null && hb.NavigateUri != null)
{
if (hb.NavigateUri.ToString().Equals(e.Uri.ToString()))
{
VisualStateManager.GoToState(hb, “ActiveLink”, true);
}
else
{
VisualStateManager.GoToState(hb, “InactiveLink”, true);
}
}
}
}
Event ile herbir sayfa navigasyon için belli işlemler yaptırılmakta.
Navigating: Bir navigasyon oluşturulma isteği anında oluşur.
private void ContentFrame_Navigating(object sender, NavigatingCancelEventArgs e)
{
MessageBox.Show(“you have navigating using mode “+ e.NavigationMode);
}
Örnekte her bir navigasyon isteği anında çalışan bir messagebox, burada NavigationMode kim navigate edilecekse edilecek navigasyonun modunu elde ediyoruz., Mesela navigasyon bir refresh yada new olabilir.
Mesela aşağıda bir linke tıklandığında ContentFrame in refresh medotu ile navigasyon olan page in tekrar refresh edilmesi isteniyor o da navigasyonun modunun refresh olduğunu gösteriyor.
NavigationFailed : Contentlerin navigasyon halinde hata olduğunda çalıştırılacak kodlar bu event da belirtilir.
Burada ErrorWindow adında oluşturduğumuz bir childclass(page değil) nesnesini gösteriyoruz show ile. Gösterdiğimiz bu sayfa (childclass) da tanımladığımız kodlarla nasıl bir hata görüntüsü çıkarılacağı ayarlanıyor. Tabiki biz childclassımızı istediğimiz yapıcı metodlarla ayarlayabiliriz yukarıdaki örnekte
public ErrorWindow(Uri uri)
{
InitializeComponent();
if (uri != null)
{
ErrorTextBox.Text = “Page not found: \”" + uri.ToString() + “\”";
}
}
Yapıcı metoda uri verilecek şekilde overload edilmiş diğer overload metodlar:
public ErrorWindow(Exception e)
{
InitializeComponent();
if (e != null)
{
ErrorTextBox.Text = e.Message + Environment.NewLine + Environment.NewLine + e.StackTrace;
}
}
public ErrorWindow(string message, string details)
{
InitializeComponent();
ErrorTextBox.Text = message + Environment.NewLine + Environment.NewLine + details;
}
Bunun la birlikte sayfamıza ok vs butonlarıda bulunacağından bununla ilgili eventlardan OK butnu için
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
NavigationStopped : navigasyon durduğunda çalışacak kodlar bu eventta belirtilir. StopLoading metodu çağrıldığında bu event çalışır.
January 11, 2011 Leave a comment
Earlier this month we announced the new Basic configuration for TFS. This configuration gives you an easy to set up version of TFS that supports source control, work items, and builds. It is a great place to migrate your Visual Source Safe assets and pick up new features in the process. Now that we have released the formal Beta 2 bits for VS2010, I wanted to do a walk through on how to get started using the system.
This post will be most helpful for those of you who have not installed or used TFS before. TFS can support sophisticated environments that include reporting, SharePoint integration, support across multiple domains, distributed databases, etc. I’m not going to cover any of that here. Instead my goal is to help you understand “why TFS” and how you can get started using the system. In a future post I will walk through the process to convert a Visual Source Safe database into TFS in case you are coming from a VSS deployment today.
First let’s talk about “why TFS?” The goal of Team Foundation Server is to create a central repository with a set of tools that make it really easy to collaborate between roles. You could try to stitch together multiple disparate systems as follows:
In this case each system has its own storage, own set of identity for assets, own commands and tools. Getting this going is like trying to hook up a set of custom stereo components: you can pull it off but it’s going to be a lot of work and you are missing out on some stuff.
What I’d rather have is a system which can integrate these items together and then enable my default work flow through the system:
This integration enables some very common scenarios. In a typical day I’m going to edit source code, build the product, test it, file bugs, fix them, lather/rinse/repeat. When the entire work flow is supported with one integrated repository then all items can be related to each other. As an example when I check in bug fixes I’d really like to see those defects resolved with the change set recorded (see sample below).
The Basic configuration of TFS allows you to do precisely this which is a big improvement over just having source control. The full version of TFS then adds new features including automated testing, virtual lab deployment, and architectural validation (to name a few). This expands your work flow as follows:
You can decide which of these new components you add when you use the Visual Studio Premium and Ultimate SKUs.
There are many ways to access TFS. As an engineer your most typical access point will be a version of Visual Studio. But if you are a tester you can use the new Test and Lab Manager product (no VS install necessary). If you are a project manager, you can also use the Web interface, Excel, Microsoft Project, or (new for VS2010) MOSS support for dashboards. More on this later.
In the rest of this post I will give you some step by step instructions on how to get going with TFS using the basic configuration for your first project.
Now that you have the conceptual level it’s time to hook things up. You should start by doing the steps listed in Brian Harry’s TFS post here. This will get all the required software on your machine with a default collection, creatively enough called DefaultCollection.
At this point we can connect to the TFS collection from Visual Studio. The easiest way to accomplish this is to use the Team Menu (you can also use the link from the home page):
You will be asked to find the Server where TFS lives. In this case my Windows 7 machine is called JLZB2REL. Add the server to the list using the Add button, then click Close:
At this point you can select the server from the combo box and then the DefaultCollection, then click Connect:
The Team Explorer tab will now have your server connection and DefaultCollection, but we don’t yet have a TFS Project to store anything in yet:
For this tutorial I have created a new Windows Form project to act as our sample solution (File, New Project, Windows Forms). If you try to add this new code project to source control, you will get an error. For example:
After you select the “Add Solution to Source Control” menu item you get the error “No team project source control folders are available.”:
The error isn’t that intuitive (especially given the word project is used for both TFS and inside your VS code solution but are different things). The error means you must create an actual TFS project to contain all of the assets for your work. In the Team Explorer, right click your collection and choose New Team Project:
In this case I’m going to create a TFS project for an Accounts Payable system. This project will contain all of the solutions, data, etc required for the overall system. After entering the data, click Next:
The Agile template is the default but you can also select CMMI. You can find more details on MSDN about the project template types. If you are using any agile methodologies (like TDD) this is a fine choice. After making a choice, just click Finish:
You will get various status updates as the project is being created:
After success, click the Close button:
Team Explorer will now have the project ready to hold Work Items, Builds, and Source Control:
At this point you can update the project collection. Let’s add the new solution to TFS again. Right click the project in the Solution Explorer and select Add Solution to Source Control:
At this point you could create a new folder in TFS for the solution or just take the default. When you are happy, click the OK button:
Upon success the Solution Explorer will now show the files are under source control (see the ‘+’ symbol in front of the files):
You will also see the list source control actions taken to publish the solution. Add a comment and then click Check-In:
Confirm the check-in by clicking Yes.
At this point your new solution is in TFS and ready for Work Items.
You can create work items directly inside Visual Studio using the Team Explorer, through the web front end, and the Test and Lab Management tool. To look at your work items, open the Team Explorer and expand the Work Items, Team Queries item. You can then double click any query (such as Active Bugs) to see any items available to you:
Our TFS project is empty so there are no active bugs in the list:
Let’s create a new item just to get us in business. Select the Team, New Work Item menu. Here you can create several types of work items to track features, defects, etc. We’ll select Bug to get going:
Enter any data you want for the new bug and click Save Work Item to commit it to the database:
If you now refresh your active bug query list, you will see the new bug:
Let’s add a real bug to fix our project. In my example I just created a default Windows Forms application. We’ll want to update the title:
Now we need to fix the bug. Navigate back to the Solution Explorer, select Form1.cs then choose Check Out for Edit:
Click the Check Out button to confirm:
The file will now have a check mark next to it so you know it is open for edit:
As you update the Text property of the main window, VS will automatically check out any dependent files for you:
This is a Windows Forms application but it works on all solution/project types. Now that we are happy with the code change, select the Pending Changes tab in the bottom of VS:
In this case we are fixing a bug, so click the Work Items icon button:
Select bug #2 which tracks our title error. We are going to resolve it with this check-in:
Add any comments you want and click Check-In, then Yes to confirm:
If you refresh bug #2, you will now see the status changed to Resolved and the history is updated:
Notice the change set (the set of source control changes) have been automatically included in the history.
At this point you could continue to create and fix bugs as required to ship your solution.
I mentioned that you don’t have to use VS itself to access the TFS repository. We’ve done a lot of deep integration with other clients like the Web and Office. As an example, I can simply pull up my web browser and go right to my server by using the server name (where 8080 is the default port): http://jlzb2rel:8080/tfs/
At this point I can explore my collections and projects. If you select the new AccountsPayable project we just created then the Continue button, you get more details. In this case by navigating to the Work Items tab I can find the bugs in the system including our newly resolved bug:
This is a really easy way to explore your project from any machine with no setup required. There is similar support for using Excel, Microsoft Project, etc. This kind of access makes it easy for all people working on your project (engineers and project managers) to work together.
At this point you have a very useful set of assets you can use to get your job done. For those of you using VSS today, you might be very happy with just this level of support. You can put down this tutorial now and come back later if you want to try some advanced features, for example the testing scenario I showed using beta 1 in this tutorial.
The next typical part of your work flow will be to automate your builds for the product. Assuming you followed Brian’s installation instructions, you now have local build support on your machine with TFS Basic. The first step is to navigate to the Team Explorer, right click on Build Definitions, and select New Build Definition:
This will give us a set of definitions to fill out, just like a code project property page:
The Trigger page allows us to decide when builds are kicked off. You have many options to pick from:
You can create and use many different build definitions which allow you to employ different build types for different purposes.
You can explore all the tabs at your leisure (each is fully documented with the product). But we need to resolve the yellow warning sign on Build Defaults by giving the build a place to store our new build, in this case a public UNC I created on my machine:
Now you can save the build definition to TFS. If we go back to the Team Explorer we can queue a build of the project:
We’ll get a confirmation dialog where we can just select the Queue button:
This will then queue off a build on my machine as shown by the status page:
If you double click the queued build you will get the detailed status of the build:
From here you can see warnings and errors, view the log file, navigate to the drop, etc. As an example if you select the “View Log File” link you can see the executed build script (subset):
If you select the Open Drop Folder link you will be taken to our drop location:
Now anyone can pick up the build and do their daily testing, release to a customer, etc.
At this point you really have everything you need to make full use of the Basic configuration of TFS.
In the future I will do a tutorial on how to hook up the Virtual Lab system (part of Visual Studio Ultimate) which allows you to deploy complex applications to a Hyper-V environment and do automated testing.
[Note this section is totally optional] You can store all of your work in one TFS Collection if you like. If you are a Visual SourceSafe user today, this is just fine and you can skip this whole section. But if you want to create a new top level collection, it is pretty easy. The first step is to start then Team Foundation Administration Console:
After the console starts, select the Team Project Collections item and click the “Create Team Project Collection” link:
Fill in a name for the project collection and any description you want, then click Next:
Accept the defaults for the data tier, then click Next:
The Basic configuration for TFS does not support Lab Management, so just click Next on this step:
At this point all the required data is configured and you can click the Verify button:
The verification step will ensure the collection can be created:
Once it passes, click the Create button:
This will provision all the required pieces of the TFS store per our configurations. Click Next and you are done:
You will now see the new project collection with the default version:
January 11, 2011 Leave a comment
.gif)
.gif)
Figure 3 The RelayCommand Classpublic class RelayCommand : ICommand
{
#region Fields
readonly Action<object> _execute;
readonly Predicate<object> _canExecute;
#endregion // Fields
#region Constructors
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
if (execute == null)
throw new ArgumentNullException("execute");
_execute = execute;
_canExecute = canExecute;
}
#endregion // Constructors
#region ICommand Members
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
return _canExecute == null ? true : _canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
_execute(parameter);
}
#endregion // ICommand Members
}
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );
}
return _saveCommand;
}
}
.gif)
Figure 5 Verifying a Property// In ViewModelBase.cs
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = "Invalid property name: " + propertyName;
if (this.ThrowOnInvalidPropertyName)
throw new Exception(msg);
else
Debug.Fail(msg);
}
}
public class CommandViewModel : ViewModelBase
{
public CommandViewModel(string displayName, ICommand command)
{
if (command == null)
throw new ArgumentNullException("command");
base.DisplayName = displayName;
this.Command = command;
}
public ICommand Command { get; private set; }
}
Figure 6 Render the List of Commands<!-- In MainWindowResources.xaml -->
<!--
This template explains how to render the list of commands on
the left side in the main window (the 'Control Panel' area).
-->
<DataTemplate x:Key="CommandsTemplate">
<ItemsControl ItemsSource="{Binding Path=Commands}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Margin="2,6">
<Hyperlink Command="{Binding Path=Command}">
<TextBlock Text="{Binding Path=DisplayName}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
Figure 7 Create the ViewModel// In App.xaml.cs
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
// Create the ViewModel to which
// the main window binds.
string path = "Data/customers.xml";
var viewModel = new MainWindowViewModel(path);
// When the ViewModel asks to be closed,
// close the window.
viewModel.RequestClose += delegate
{
window.Close();
};
// Allow all controls in the window to
// bind to the ViewModel by setting the
// DataContext, which propagates down
// the element tree.
window.DataContext = viewModel;
window.Show();
}
<!-- In MainWindow.xaml -->
<Menu>
<MenuItem Header="_File">
<MenuItem Header="_Exit" Command="{Binding Path=CloseCommand}" />
</MenuItem>
<MenuItem Header="_Edit" />
<MenuItem Header="_Options" />
<MenuItem Header="_Help" />
</Menu>
<DataTemplate x:Key="ClosableTabItemTemplate">
<DockPanel Width="120">
<Button
Command="{Binding Path=CloseCommand}"
Content="X"
DockPanel.Dock="Right"
Width="16" Height="16"
/>
<ContentPresenter Content="{Binding Path=DisplayName}" />
</DockPanel>
</DataTemplate>
Figure 8 Removing Workspace from the UI// In MainWindowViewModel.cs
ObservableCollection<WorkspaceViewModel> _workspaces;
public ObservableCollection<WorkspaceViewModel> Workspaces
{
get
{
if (_workspaces == null)
{
_workspaces = new ObservableCollection<WorkspaceViewModel>();
_workspaces.CollectionChanged += this.OnWorkspacesChanged;
}
return _workspaces;
}
}
void OnWorkspacesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count != 0)
foreach (WorkspaceViewModel workspace in e.NewItems)
workspace.RequestClose += this.OnWorkspaceRequestClose;
if (e.OldItems != null && e.OldItems.Count != 0)
foreach (WorkspaceViewModel workspace in e.OldItems)
workspace.RequestClose -= this.OnWorkspaceRequestClose;
}
void OnWorkspaceRequestClose(object sender, EventArgs e)
{
this.Workspaces.Remove(sender as WorkspaceViewModel);
}
Figure 9 The Test Method// In MainWindowViewModelTests.cs
[TestMethod]
public void TestCloseAllCustomersWorkspace()
{
// Create the MainWindowViewModel, but not the MainWindow.
MainWindowViewModel target =
new MainWindowViewModel(Constants.CUSTOMER_DATA_FILE);
Assert.AreEqual(0, target.Workspaces.Count, "Workspaces isn't empty.");
// Find the command that opens the "All Customers" workspace.
CommandViewModel commandVM =
target.Commands.First(cvm => cvm.DisplayName == "View all customers");
// Open the "All Customers" workspace.
commandVM.Command.Execute(null);
Assert.AreEqual(1, target.Workspaces.Count, "Did not create viewmodel.");
// Ensure the correct type of workspace was created.
var allCustomersVM = target.Workspaces[0] as AllCustomersViewModel;
Assert.IsNotNull(allCustomersVM, "Wrong viewmodel type created.");
// Tell the "All Customers" workspace to close.
allCustomersVM.CloseCommand.Execute(null);
Assert.AreEqual(0, target.Workspaces.Count, "Did not close viewmodel.");
}
Figure 10 Supplying a View<!--
This resource dictionary is used by the MainWindow.
-->
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:DemoApp.ViewModel"
xmlns:vw="clr-namespace:DemoApp.View"
>
<!--
This template applies an AllCustomersView to an instance
of the AllCustomersViewModel class shown in the main window.
-->
<DataTemplate DataType="{x:Type vm:AllCustomersViewModel}">
<vw:AllCustomersView />
</DataTemplate>
<!--
This template applies a CustomerView to an instance
of the CustomerViewModel class shown in the main window.
-->
<DataTemplate DataType="{x:Type vm:CustomerViewModel}">
<vw:CustomerView />
</DataTemplate>
<!-- Other resources omitted for clarity... -->
</ResourceDictionary>
public string FirstName
{
get { return _customer.FirstName; }
set
{
if (value == _customer.FirstName)
return;
_customer.FirstName = value;
base.OnPropertyChanged("FirstName");
}
}
.gif)
Figure 12 The Test Method// In CustomerViewModelTests.cs
[TestMethod]
public void TestCustomerType()
{
Customer cust = Customer.CreateNewCustomer();
CustomerRepository repos = new CustomerRepository(
Constants.CUSTOMER_DATA_FILE);
CustomerViewModel target = new CustomerViewModel(cust, repos);
target.CustomerType = "Company"
Assert.IsTrue(cust.IsCompany, "Should be a company");
target.CustomerType = "Person";
Assert.IsFalse(cust.IsCompany, "Should be a person");
target.CustomerType = "(Not Specified)";
string error = (target as IDataErrorInfo)["CustomerType"];
Assert.IsFalse(String.IsNullOrEmpty(error), "Error message should
be returned");
}
Figure 13 CustomerType Properties// In CustomerViewModel.cs
public string[] CustomerTypeOptions
{
get
{
if (_customerTypeOptions == null)
{
_customerTypeOptions = new string[]
{
"(Not Specified)",
"Person",
"Company"
};
}
return _customerTypeOptions;
}
}
public string CustomerType
{
get { return _customerType; }
set
{
if (value == _customerType ||
String.IsNullOrEmpty(value))
return;
_customerType = value;
if (_customerType == "Company")
{
_customer.IsCompany = true;
}
else if (_customerType == "Person")
{
_customer.IsCompany = false;
}
base.OnPropertyChanged("CustomerType");
base.OnPropertyChanged("LastName");
}
}
<ComboBox
ItemsSource="{Binding CustomerTypeOptions}"
SelectedItem="{Binding CustomerType, ValidatesOnDataErrors=True}"
/>
Figure 14 Validating a CustomerViewModel Object// In CustomerViewModel.cs
string IDataErrorInfo.this[string propertyName]
{
get
{
string error = null;
if (propertyName == "CustomerType")
{
// The IsCompany property of the Customer class
// is Boolean, so it has no concept of being in
// an "unselected" state. The CustomerViewModel
// class handles this mapping and validation.
error = this.ValidateCustomerType();
}
else
{
error = (_customer as IDataErrorInfo)[propertyName];
}
// Dirty the commands registered with CommandManager,
// such as our Save command, so that they are queried
// to see if they can execute now.
CommandManager.InvalidateRequerySuggested();
return error;
}
}
string ValidateCustomerType()
{
if (this.CustomerType == "Company" ||
this.CustomerType == "Person")
return null;
return "Customer type must be selected";
}
Figure 15 The Save Logic for CustomerViewModel// In CustomerViewModel.cs
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(
param => this.Save(),
param => this.CanSave
);
}
return _saveCommand;
}
}
public void Save()
{
if (!_customer.IsValid)
throw new InvalidOperationException("...");
if (this.IsNewCustomer)
_customerRepository.AddCustomer(_customer);
base.OnPropertyChanged("DisplayName");
}
bool IsNewCustomer
{
get
{
return !_customerRepository.ContainsCustomer(_customer);
}
}
bool CanSave
{
get
{
return
String.IsNullOrEmpty(this.ValidateCustomerType()) &&
_customer.IsValid;
}
}
Figure 16 CollectionViewSource<!-- In AllCustomersView.xaml -->
<CollectionViewSource
x:Key="CustomerGroups"
Source="{Binding Path=AllCustomers}"
>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="IsCompany" />
</CollectionViewSource.GroupDescriptions>
<CollectionViewSource.SortDescriptions>
<!--
Sort descending by IsCompany so that the ' True' values appear first,
which means that companies will always be listed before people.
-->
<scm:SortDescription PropertyName="IsCompany" Direction="Descending" />
<scm:SortDescription PropertyName="DisplayName" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
<Style x:Key="CustomerItemStyle" TargetType="{x:Type ListViewItem}">
<!-- Stretch the content of each cell so that we can
right-align text in the Total Sales column. -->
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<!--
Bind the IsSelected property of a ListViewItem to the
IsSelected property of a CustomerViewModel object.
-->
<Setter Property="IsSelected" Value="{Binding Path=IsSelected,
Mode=TwoWay}" />
</Style>
Figure 17 Monitoring for Selected or Unselected// In AllCustomersViewModel.cs
public double TotalSelectedSales
{
get
{
return this.AllCustomers.Sum(
custVM => custVM.IsSelected ? custVM.TotalSales : 0.0);
}
}
void OnCustomerViewModelPropertyChanged(object sender,
PropertyChangedEventArgs e)
{
string IsSelected = "IsSelected";
// Make sure that the property name we're
// referencing is valid. This is a debugging
// technique, and does not execute in a Release build.
(sender as CustomerViewModel).VerifyPropertyName(IsSelected);
// When a customer is selected or unselected, we must let the
// world know that the TotalSelectedSales property has changed,
// so that it will be queried again for a new value.
if (e.PropertyName == IsSelected)
this.OnPropertyChanged("TotalSelectedSales");
}
<!-- In AllCustomersView.xaml -->
<StackPanel Orientation="Horizontal">
<TextBlock Text="Total selected sales: " />
<ContentPresenter
Content="{Binding Path=TotalSelectedSales}"
ContentStringFormat="c"
/>
</StackPanel>