WPF Development, Change Control Appearance

Windows Presentation Foundation (WPF) is a powerful platform that is part of the .NET framework, allowing for the creation of rich user interfaces. One of the biggest advantages of WPF is that it provides a variety of UI controls and enables easy design and styling of them. This article will detail various ways to change the appearance of controls in WPF.

Basic Structure of WPF Controls

WPF controls are defined in XAML (Extensible Application Markup Language). XAML is a language that allows you to declaratively code user interfaces. Let’s look at various controls provided by WPF, such as Button, TextBox, and ComboBox.

Example: Basic Button

<Button Name="myButton" Content="Click Me!" />

The above XAML is code that creates a basic button. By default, styles are applied depending on the system theme.

Changing Control Styles

The most common way to change the appearance of controls in WPF is to use styles. Styles are XAML objects used to define the visual characteristics of a specific control.

Defining a Style

Styles can be defined within the Window.Resources or Application.Resources elements. Below is an example of a style that changes the background color and font of a button.

Example: Button Style


<Window x:Class="MyApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Background" Value="LightBlue"/>
            <Setter Property="Foreground" Value="DarkBlue"/>
            <Setter Property="FontSize" Value="16"/>
        </Style>
    </Window.Resources>

    <Grid>
        <Button Content="Button with Style" />
    </Grid>
</Window>

The above code sets the background color of all buttons to LightBlue and the foreground color to DarkBlue. By defining a style in this way, developers do not need to set the properties of the button separately; the style is applied automatically.

Using Control Triggers

Triggers allow you to dynamically change styles when certain conditions are met. For example, you can add a trigger that changes the color when the mouse hovers over a button.

Example: Mouse Over Trigger


<Style TargetType="Button">
    <Setter Property="Background" Value="LightBlue"/>
    <Setter Property="Foreground" Value="DarkBlue"/>
    <Setter Property="FontSize" Value="16"/>

    <Style.Triggers>
        <Trigger Property="IsMouseOver" Value="True">
            <Setter Property="Background" Value="DarkBlue"/>
            <Setter Property="Foreground" Value="White"/>
        </Trigger>
    </Style.Triggers>
</Style>

In the above code, when the IsMouseOver property is true, the button’s background color and foreground color change. Triggers are a very useful tool for enhancing user experience.

Customization Using ControlTemplate

If you want to specify the appearance of a control more precisely, you can use ControlTemplate. A ControlTemplate defines the internal structure of a control, allowing you to replace the provided visual elements with completely different shapes.

Example: Changing Button ControlTemplate


<Style TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border Background="{TemplateBinding Background}" 
                        BorderBrush="Black" 
                        BorderThickness="2" 
                        CornerRadius="10">
                    <ContentPresenter HorizontalAlignment="Center" 
                                      VerticalAlignment="Center"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

When this style is applied to a button, the default button shape disappears, and the content is displayed within a Border element with rounded corners. The button’s background color is bound to the custom style through TemplateBinding.

Styling List Items through Data Templates

In WPF, you can use data templates to define the presentation of items in controls like ItemsControl, ListBox, and ComboBox. By using data templates, you can freely place all UI elements needed to visually represent complex data.

Example: Using Data Templates


<Window.Resources>
    <DataTemplate x:Key="PersonTemplate">
        <StackPanel Orientation="Horizontal">
            <Ellipse Width="30" Height="30" Fill="LightGreen"/>
            <TextBlock Text="{Binding Name}" Margin="5" FontSize="14"/>
        </StackPanel>
    </DataTemplate>
</Window.Resources>

<ListBox ItemTemplate="{StaticResource PersonTemplate}">
    <ListBoxItem Content="{Binding Name='Hong Gil-dong'}"/>
    <ListBoxItem Content="{Binding Name='Lee Sun-shin'}"/>
</ListBox>

In the above example, the DataTemplate defines each data item with a StackPanel, displaying a circular graphic along with the item’s name. This effectively connects data and UI for representation.

Adding Visual Effects through Animation

WPF supports easy addition of animations through XAML. By incorporating animations, you can enrich the user experience.

Example: Button Animation


<Button Name="myAnimatedButton" Content="Animated Button">
    <Button.Resources>
        <Storyboard x:Key="MyAnimation">
            <DoubleAnimation 
                Storyboard.TargetProperty="Opacity"
                From="1" To="0.5" Duration="0:0:1" 
                AutoReverse="True"
                RepeatBehavior="Forever"/>
        </Storyboard>
    </Button.Resources>
    <Button.Triggers>
        <EventTrigger RoutedEvent="Button.MouseEnter">
            <BeginStoryboard Storyboard="{StaticResource MyAnimation}" />
        </EventTrigger>
    </Button.Triggers>
</Button>

This code applies an Opacity animation to the button when the mouse hovers over it, giving a faded effect as it becomes semi-transparent and then reappears. Using animations, you can create aesthetically appealing UIs.

Conclusion

WPF is a powerful and flexible tool for designing user interfaces in various ways. Through fundamental styles, triggers, templates, data templates, and animations, developers can enhance user experience and build more beautiful interfaces. As you continue developing in WPF, consider utilizing various styles and templates. These techniques will ultimately contribute to creating better software.

WPF Development, Events

WPF (Windows Presentation Foundation) is a powerful and flexible tool used to create Windows applications. It provides various elements for constructing the user interface (UI), and these elements utilize events to respond to user interactions. This article will take a deep dive into the event system of WPF and help you gain practical understanding through example code.

What is an Event?

An event is a notification of a specific action or state change that occurs from a user or the system. In WPF, various elements (buttons, text boxes, etc.) can raise specific events, and developers can register listeners (handlers) for these events to respond to user inputs or system actions.

WPF Event Model

WPF is primarily based on the .NET event model and includes the following two main elements:

  • Events: Signals that represent interactions between the user and the system.
  • Event Handlers: Methods that execute when a specific event occurs.

The WPF event model has the following form:

 
public event EventHandler MyEvent;

In the above code, MyEvent is a user-defined event, and EventHandler is a built-in delegate. Generally, events are called when a specific situation occurs (clicking, mouse movement, etc.).

Using Events in WPF

To use events in WPF, you follow these two steps:

  1. Raising Events: WPF UI elements (buttons, checkboxes, etc.) provide various events, and developers can add these events to UI elements.
  2. Registering Event Handlers: Implement methods that define the actions to be performed when an event occurs and connect them to the event.

Event Example

In this example, we will create a simple WPF application that outputs a message when the user clicks a button.

XAML Code

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="WPF Event Example" Height="200" Width="300">
    <Grid>
        <Button Name="myButton" Content="Please Click" Click="MyButton_Click" Width="200" Height="100" />
    </Grid>
</Window>

C# Code

using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void MyButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("The button has been clicked!");
        }
    }
}

In the above code, the MyButton_Click method is called when the button is clicked. The MessageBox.Show function informs the user that the button has been clicked.

Event Arguments

In WPF, event handlers typically have two parameters:

  • sender: The object that raised the event.
  • e: An object that contains data about the event.

An example of utilizing event arguments is as follows:

private void MyButton_Click(object sender, RoutedEventArgs e)
{
    Button clickedButton = sender as Button;
    MessageBox.Show(clickedButton.Content + " button has been clicked!");
}

Handling Multiple Events

It is possible to handle various events of different UI elements within a single method. Let’s examine this through the example below.

XAML Code

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Handling Various Events" Height="250" Width="250">
    <StackPanel>
        <Button Name="button1" Content="Button 1" Click="AnyButton_Click" Width="100" Height="30" />
        <Button Name="button2" Content="Button 2" Click="AnyButton_Click" Width="100" Height="30" />
        <Button Name="button3" Content="Button 3" Click="AnyButton_Click" Width="100" Height="30" />
    </StackPanel>
</Window>

C# Code

using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void AnyButton_Click(object sender, RoutedEventArgs e)
        {
            Button clickedButton = sender as Button;
            MessageBox.Show(clickedButton.Content + " has been clicked.");
        }
    }
}

In the above example, there are three buttons, each registered with the same event handler (AnyButton_Click). When the user clicks a button, the name of that button is displayed in a message box.

Removing Events

Event handlers can be removed as needed. Below is a simple example that removes an event handler.

XAML Code

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Event Removal Example" Height="200" Width="300">
    <StackPanel>
        <Button Name="myButton" Content="Please Click" Click="AddClick" Width="200" Height="100" />
        <Button Name="removeButton" Content="Remove Event" Click="RemoveClick" Width="200" Height="100" />
    </StackPanel>
</Window>

C# Code

using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void AddClick(object sender, RoutedEventArgs e)
        {
            myButton.Click += MyButton_Click;
            MessageBox.Show("The event has been added.");
        }

        private void RemoveClick(object sender, RoutedEventArgs e)
        {
            myButton.Click -= MyButton_Click;
            MessageBox.Show("The event has been removed.");
        }

        private void MyButton_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("The button has been clicked!");
        }
    }
}

The above code demonstrates how to dynamically add and remove events when the user clicks a button. The += symbol is used to add an event handler, and the -= symbol is used to remove it.

Creating Custom Events

Developers can create custom events for WPF elements. To do this, the event keyword is used to define a new event.

public class MyButton : Button
{
    public event RoutedEventHandler MyCustomEvent;

    protected virtual void OnMyCustomEvent()
    {
        MyCustomEvent?.Invoke(this, new RoutedEventArgs());
    }

    protected override void OnClick()
    {
        base.OnClick();
        OnMyCustomEvent();
    }
}

The above code defines a custom button class that raises MyCustomEvent when clicked by the user. When the button is clicked, MyCustomEvent is triggered.

Conclusion

In WPF, events are a crucial element for handling user interactions. By understanding events and event handlers, developers can build more interactive and responsive applications. This article has practiced the basic event system, event handling, and creation of custom events, demonstrating how to implement smooth interactions between users and applications.

Continue to learn about the various events and their usages provided by WPF and try to apply them in your projects. Happy Coding!

WPF Development, Practice Discussion Page Creation

WPF (Windows Presentation Foundation) is a very useful technology for designing and developing Windows applications. In this tutorial, we will learn how to create a simple discussion page using WPF. This tutorial will cover the basic concepts of WPF, along with practical projects utilizing data binding, event handling, custom controls, and the MVVM (Model-View-ViewModel) pattern.

1. What is WPF?

WPF is a UI framework developed by Microsoft, based on the .NET Framework. With WPF, you can easily and quickly create advanced user interfaces, and develop visually appealing applications with vector graphics, styling, and templating features.

2. Key Features of WPF

  • XAML (Extensible Application Markup Language) based UI design
  • Efficient UI work through data binding
  • Improved code separation and maintainability through the MVVM pattern
  • Various multimedia capabilities including 3D graphics and animations
  • Support for effective collaboration between design and development

3. Designing the Discussion Page

In this project, we will design a discussion page with the following features.

  • A text box where users can enter their opinions
  • When the submit button is clicked, the opinion is added to the list
  • A button to delete submitted opinions

4. Project Setup

Open Visual Studio and create a new WPF application project. Set the project name to “DiscussionPage”. You can design the UI in the automatically generated MainWindow.xaml file.

5. XAML UI Design


<Window x:Class="DiscussionPage.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Discussion Page" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <StackPanel Orientation="Horizontal">
            <TextBox x:Name="CommentTextBox" Width="600" Height="30" Margin="10" PlaceholderText="Enter your opinion..." />
            <Button x:Name="SubmitButton" Content="Submit" Width="80" Height="30" Click="SubmitButton_Click" Margin="10"/>
        </StackPanel>

        <ListBox x:Name="CommentsListBox" Grid.Row="1" Margin="10" />
    </Grid>
</Window>

6. Code Behind

The UI is ready, so now we prepare to write C# code to handle user input. Write the following in the MainWindow.xaml.cs file.


using System;
using System.Collections.ObjectModel;
using System.Windows;

namespace DiscussionPage
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<string> Comments { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            Comments = new ObservableCollection<string>();
            CommentsListBox.ItemsSource = Comments;
        }

        private void SubmitButton_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(CommentTextBox.Text))
            {
                Comments.Add(CommentTextBox.Text);
                CommentTextBox.Clear();
            }
            else
            {
                MessageBox.Show("Please enter your opinion.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }
    }
}

7. Code Explanation

The most important part of the above code is the use of ObservableCollection to perform data binding with the list box. When the user submits an opinion, the entered opinion is added to the list and reflected in the UI in real-time.

8. Feature Expansion – Adding Delete Functionality

Let’s add a feature to delete the opinions registered by the users. We will add a button to remove the selected item from the list box.


<Button x:Name="DeleteButton" Content="Delete" Width="80" Height="30" Click="DeleteButton_Click" Margin="10"/>

9. Adding Delete Button Event Handler


private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
    string selectedComment = (string)CommentsListBox.SelectedItem;
    if (selectedComment != null)
    {
        Comments.Remove(selectedComment);
    }
    else
    {
        MessageBox.Show("Please select an opinion to delete.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
    }
}

10. Final Check and Execution

All the code and UI are complete. You can now run the project to test the implemented features. When a user enters an opinion and submits it, it will be added to the list, and the selected opinion can be deleted.

11. Additional Feature Considerations

Now that the project has basic functionality, here are some additional features to consider:

  • Comment feature for opinions
  • Like feature for comments
  • Adding a name field for the opinion writer
  • API connections for extension to a web application

12. Conclusion

In this tutorial, we created a simple discussion page using WPF. I hope it served as a great opportunity to learn the basic concepts of WPF, data binding, and the importance of event handling and the MVVM pattern.

I encourage you to expand your skills through more projects and practice with WPF. For example, this project could be improved and changed into a web application.

I look forward to your support and feedback. Good luck!

WPF Development, Practice Display Products and Details

WPF (Windows Presentation Foundation) is a powerful UI framework based on the .NET Framework. It is particularly well-suited for developing desktop applications. In this course, we will learn how to display product lists and information details using WPF. Topics covered in this course include product data binding, implementing the MVVM (Model-View-ViewModel) pattern, and UI design using XAML.

1. Preparation Tasks

To create a WPF application, you must first install Visual Studio and create a new WPF application project. Let’s set up the new project by following the steps below.

  1. Launch Visual Studio.
  2. In the File menu, select New -> Project.
  3. From the project templates, select WPF App (.NET Core) or WPF App (.NET Framework).
  4. Specify the project name and storage path, then click Create.

2. Understanding the MVVM Pattern

The MVVM (Model-View-ViewModel) pattern is an architecture pattern primarily used in WPF that helps to separate the user interface (UI) from business logic. The three components of this pattern are as follows:

  • Model: Business logic and data.
  • View: User interface.
  • ViewModel: Mediator between View and Model.

In this course, we will create a simple product information application while applying the MVVM pattern.

3. Creating Data Model

First, let’s create a Product class to hold product information. This class will have properties for the product’s name, price, and description.

using System.ComponentModel;

public class Product : INotifyPropertyChanged
{
    private string _name;
    private decimal _price;
    private string _description;

    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    public decimal Price
    {
        get => _price;
        set
        {
            _price = value;
            OnPropertyChanged(nameof(Price));
        }
    }

    public string Description
    {
        get => _description;
        set
        {
            _description = value;
            OnPropertyChanged(nameof(Description));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

The above code implements the INotifyPropertyChanged interface to allow notifications when properties change. This is useful for data binding.

4. Creating ViewModel

Next, we will create a ProductViewModel class to implement the logic that manages the product list. This ViewModel includes a list of products and displays the details of the selected product.

using System.Collections.ObjectModel;
using System.Windows.Input;

public class ProductViewModel : INotifyPropertyChanged
{
    private Product _selectedProduct;

    public ObservableCollection<Product> Products { get; }

    public Product SelectedProduct
    {
        get => _selectedProduct;
        set
        {
            _selectedProduct = value;
            OnPropertyChanged(nameof(SelectedProduct));
        }
    }

    public ProductViewModel()
    {
        Products = new ObservableCollection<Product>
        {
            new Product { Name = "Laptop", Price = 1200000, Description = "High-performance laptop." },
            new Product { Name = "Smartphone", Price = 800000, Description = "Latest smartphone." },
            new Product { Name = "Tablet", Price = 500000, Description = "Portable tablet." }
        };
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Here, we use ObservableCollection<Product> to manage the product list. ObservableCollection automatically reflects changes in the collection in the UI.

5. UI Design Using XAML

Now, let’s design the user interface using XAML. We will bind the UI with the ProductViewModel created earlier.

<Window x:Class="ProductApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Product List" Height="350" Width="525">
    <Window.DataContext>
        <local:ProductViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="3*"/>
        </Grid.ColumnDefinitions>

        <ListBox ItemsSource="{Binding Products}" 
                 SelectedItem="{Binding SelectedProduct}" 
                 DisplayMemberPath="Name" 
                 Margin="10" />

        <StackPanel Grid.Column="1" Margin="10">
            <TextBlock Text="Product Name:" FontWeight="Bold"/>
            <TextBlock Text="{Binding SelectedProduct.Name}" />

            <TextBlock Text="Price:" FontWeight="Bold"/>
            <TextBlock Text="{Binding SelectedProduct.Price, StringFormat={}{0:C}}" />

            <TextBlock Text="Description:" FontWeight="Bold"/>
            <TextBlock Text="{Binding SelectedProduct.Description}" TextWrapping="Wrap" />
        </StackPanel>

    </Grid>
</Window>

The above XAML code sets up a basic layout and uses a ListBox to display the product list. When a user selects a product from the ListBox, the details of the selected product are displayed in the right area.

6. Running the Application and Checking Results

Now that all the code has been written, let’s run the application to check the results. By pressing the F5 key to run it in debug mode, you will see the UI as shown below.

Product List Application

7. Conclusion

In this course, we created a simple product list and details application using WPF. By applying the MVVM pattern, we separated Model, View, and ViewModel, enhancing code readability and maintainability. We were able to easily implement the connection between the user interface and business logic by utilizing WPF’s data binding capabilities.
I hope this course has enhanced your understanding of fundamental data binding and MVVM in WPF.

Moving forward, I encourage you to develop more complex and diverse WPF applications. Utilize the various features of WPF to create even more appealing user interfaces!

WPF Development, Creating Practice Applications and Contact Pages

This article will cover how to create a basic application and contact page using WPF (Windows Presentation Foundation). WPF is based on the .NET Framework and provides powerful UI design and data binding capabilities. We will develop a simple contact management application.

1. What is WPF?

WPF is a UI framework provided by Microsoft that helps build complex desktop applications. WPF uses XAML (Extensible Application Markup Language) to define the user interface and allows you to implement application logic using .NET languages.

Key advantages of WPF include:

  • Excellent data binding capabilities.
  • Powerful graphics and animation rendering.
  • Support for MVVM (Model-View-ViewModel) design pattern.
  • Providing a variety of UI controls.

2. Project Setup

Let’s explain how to create a WPF application in Visual Studio.

  1. Run Visual Studio and select “Create a new project”.
  2. Select WPF Application and name the project “ContactManager”.
  3. Once the project is created, you will find the preprovided MainWindow.xaml file.

3. Basic UI Layout using XAML

XAML is the markup language that defines the user interface in WPF. Below is the XAML code that sets up a basic contact management UI.

<Window x:Class="ContactManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Contact Management" Height="350" Width="525">
    <Grid>
        <TextBox x:Name="txtName" Width="200" Height="25" Margin="10" PlaceholderText="Enter Name"/>
        <TextBox x:Name="txtPhone" Width="200" Height="25" Margin="10,40,10,10" PlaceholderText="Enter Phone Number"/>
        <Button x:Name="btnAdd" Content="Add" Width="75" Height="25" Margin="10,80,10,10" Click="BtnAdd_Click"/>
        <ListBox x:Name="lstContacts" Margin="220,10,10,10"></ListBox>
    </Grid>
</Window>

The above XAML code includes two text boxes for entering a name and phone number, a list box to display the contact list, and a button to add contacts.

4. Implementing Business Logic with C#

Now let’s write the business logic for the UI created with XAML. Add the following code to the MainWindow.xaml.cs file.

using System;
    using System.Collections.Generic;
    using System.Windows;

    namespace ContactManager
    {
        public partial class MainWindow : Window
        {
            private List<Contact> contacts = new List<Contact>();

            public MainWindow()
            {
                InitializeComponent();
            }

            private void BtnAdd_Click(object sender, RoutedEventArgs e)
            {
                var name = txtName.Text;
                var phone = txtPhone.Text;

                if (!string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(phone))
                {
                    var contact = new Contact { Name = name, PhoneNumber = phone };
                    contacts.Add(contact);
                    UpdateContactList();
                    ClearInputs();
                }
                else
                {
                    MessageBox.Show("Please enter name and phone number.");
                }
            }

            private void UpdateContactList()
            {
                lstContacts.Items.Clear();
                foreach (var contact in contacts)
                {
                    lstContacts.Items.Add(contact.ToString());
                }
            }

            private void ClearInputs()
            {
                txtName.Clear();
                txtPhone.Clear();
            }
        }

        public class Contact
        {
            public string Name { get; set; }
            public string PhoneNumber { get; set; }

            public override string ToString()
            {
                return $"{Name} ({PhoneNumber})";
            }
        }
    }

This code enables the user to input a name and phone number and add the contact to the list when the ‘Add’ button is clicked. It checks that the input values are not empty, updates the contact list, and clears the input fields.

5. Applying the MVVM Pattern

Now, let’s implement the MVVM pattern. MVVM is a design pattern that increases maintainability and testability in WPF applications. We will use the following structure:

  • Model: Data structure and business logic.
  • View: UI layout.
  • ViewModel: Manages the connection and data binding between View and Model.

5.1. Model Class

public class Contact
    {
        public string Name { get; set; }
        public string PhoneNumber { get; set; }

        public override string ToString()
        {
            return $"{Name} ({PhoneNumber})";
        }
    }

5.2. ViewModel Class

using System.Collections.ObjectModel;
    using System.Windows.Input;

    public class ContactViewModel : BaseViewModel
    {
        public ObservableCollection<Contact> Contacts { get; set; } = new ObservableCollection<Contact>();
        private string name;
        private string phoneNumber;

        public string Name
        {
            get { return name; }
            set { name = value; OnPropertyChanged(); }
        }

        public string PhoneNumber
        {
            get { return phoneNumber; }
            set { phoneNumber = value; OnPropertyChanged(); }
        }

        public ICommand AddCommand { get; set; }

        public ContactViewModel()
        {
            AddCommand = new RelayCommand(AddContact);
        }

        private void AddContact()
        {
            if (!string.IsNullOrWhiteSpace(Name) && !string.IsNullOrWhiteSpace(PhoneNumber))
            {
                var contact = new Contact { Name = Name, PhoneNumber = PhoneNumber };
                Contacts.Add(contact);
                ClearInputs();
            }
        }

        private void ClearInputs()
        {
            Name = string.Empty;
            PhoneNumber = string.Empty;
        }
    }

5.3. BaseViewModel Class

using System.ComponentModel;

    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

5.4. RelayCommand Class

using System;
    using System.Windows.Input;

    public class RelayCommand : ICommand
    {
        private readonly Action execute;
        private readonly Func<bool> canExecute;

        public event EventHandler CanExecuteChanged;

        public RelayCommand(Action execute, Func<bool> canExecute = null)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return canExecute == null || canExecute();
        }

        public void Execute(object parameter)
        {
            execute();
        }

        public void RaiseCanExecuteChanged()
        {
            CanExecuteChanged?.Invoke(this, EventArgs.Empty);
        }
    }

5.5. View Update

Now we will modify MainWindow.xaml to apply ViewModel and data binding:

<Window x:Class="ContactManager.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:ContactManager"
            Title="Contact Management" Height="350" Width="525">
    <Window.DataContext>
        <local:ContactViewModel />
    </Window.DataContext>
    <Grid>
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Width="200" Height="25" Margin="10" PlaceholderText="Enter Name"/>
        <TextBox Text="{Binding PhoneNumber, UpdateSourceTrigger=PropertyChanged}" Width="200" Height="25" Margin="10,40,10,10" PlaceholderText="Enter Phone Number"/>
        <Button Command="{Binding AddCommand}" Content="Add" Width="75" Height="25" Margin="10,80,10,10"/>
        <ListBox ItemsSource="{Binding Contacts}" Margin="220,10,10,10">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

6. Check the Results

When you run the application, the user interface will be displayed. Enter the name and phone number and click the ‘Add’ button to add a contact. The contact should be added to the list, and you will experience cleaner and more maintainable code compared to using control structures without the MVVM pattern.

7. Conclusion

In this tutorial, we explored how to create a basic contact management application using WPF. We demonstrated how applying the MVVM pattern in WPF can enhance code reusability and testability. In the future, try adding more complex features while utilizing various capabilities of WPF.

8. References

WPF is an evolving technology. Continue learning and practicing to become a better developer.