Blazor Todo リスト アプリを構築する

注意

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

このチュートリアルでは、Blazor アプリを構築および変更するための基本的な作業エクスペリエンスを提供します。 Blazor の詳細なガイダンスについては、Blazor のリファレンス ドキュメントを参照してください。

具体的には、次の方法を学習します。

  • Todo リストの Blazor アプリ プロジェクトを作成する
  • Razor コンポーネントを変更する
  • コンポーネントでイベント処理とデータ バインディングを使用する
  • Blazor アプリでルーティングを使用する

このチュートリアルの最後には、動作する ToDo リスト アプリが完成します。

前提条件

まだシステムにインストールされていない場合、またはシステムに最新バージョンがインストールされていない場合は、.NET をダウンロードしてインストールします

Blazor アプリを作成する

コマンド シェルで TodoList という名前の新しい Blazor Web アプリを作成します。

dotnet new blazor -o TodoList

-o|--output オプションを指定すると、プロジェクト用のフォルダーが作成されます。 プロジェクト用のフォルダーを作成し、そのフォルダーでコマンド シェルが開いている場合は、-o|--output オプションと値を省略してプロジェクトを作成します。

次のいずれかのホスティング モデルを使用してコマンド シェルで TodoList という名前の新しい Blazor アプリを作成します。

  • Blazor Server を使用したエクスペリエンスでは、次のコマンドを使用してアプリを作成します。

    dotnet new blazorserver -o TodoList
    
  • Blazor WebAssembly を使用したエクスペリエンスでは、次のコマンドを使用してアプリを作成します。

    dotnet new blazorwasm -o TodoList
    

上記のコマンドでは、アプリを保持するために -o|--output オプションを指定して、TodoList という名前のフォルダーを作成します。 TodoList フォルダーは、プロジェクトのルート フォルダーです。 次のコマンドを使用して、ディレクトリを TodoList フォルダーに変更します。

cd TodoList

Todo リスト Blazor アプリを構築する

次のコマンドを使用して、新しい TodoRazor コンポーネントをアプリに追加します。

dotnet new razorcomponent -n Todo -o Components/Pages

前のコマンドの -n|--name オプションで、新しい Razor コンポーネントの名前を指定します。 新しいコンポーネントは、-o|--output オプションを使用してプロジェクトの Components/Pages フォルダーに作成されます。

dotnet new razorcomponent -n Todo -o Pages

前のコマンドの -n|--name オプションで、新しい Razor コンポーネントの名前を指定します。 新しいコンポーネントは、-o|--output オプションを使用してプロジェクトの Pages フォルダーに作成されます。

重要

Razor コンポーネント ファイル名の先頭文字は、大文字である必要があります。 Pages フォルダーを開き、Todo コンポーネントのファイル名の先頭が大文字 T であることを確認します。 ファイル名は Todo.razor のはずです。

任意のファイル エディターで Todo コンポーネントを開き、ファイルの先頭で次の変更を行います。

  • 相対 URL /todo とともに @pageRazor ディレクティブを追加します。
  • そのまま静的にレンダリングされないように、ページの対話機能を有効にします。 対話型サーバー レンダリング モードにすると、コンポーネントでサーバーからの UI イベントを処理できます。
  • ページに HTML <title> 要素を追加することを可能にする PageTitle コンポーネントを使用してページ タイトルを追加します。

任意のファイル エディターで Todo コンポーネントを開き、ファイルの先頭で次の変更を行います。

  • 相対 URL /todo とともに @pageRazor ディレクティブを追加します。
  • ページに HTML <title> 要素を追加することを可能にする PageTitle コンポーネントを使用してページ タイトルを追加します。

任意のファイル エディターで Todo コンポーネントを開き、相対 URL /todo とともに @pageRazor ディレクティブを追加します。

Todo.razor:

@page "/todo"
@rendermode InteractiveServer

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

@code {

}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

@code {

}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

@code {

}
@page "/todo"

<h3>Todo</h3>

@code {

}
@page "/todo"

<h3>Todo</h3>

@code {

}

Todo.razor ファイルを保存します。

ナビゲーション バーに Todo コンポーネントを追加します。

NavMenu コンポーネントはアプリのレイアウトで使用されます。 レイアウトは、アプリ内でのコンテンツの重複を回避できるようにするコンポーネントです。 アプリによってコンポーネントの URL が読み込まれるときに、NavLink コンポーネントによりそのアプリの UI でキューが指定されます。

NavMenu コンポーネントのナビゲーション要素 (<nav>) コンテンツに、次に示す Todo コンポーネントの <div> 要素を追加します。

Components/Layout/NavMenu.razor:

Shared/NavMenu.razor:

<div class="nav-item px-3">
    <NavLink class="nav-link" href="todo">
        <span class="oi oi-list-rich" aria-hidden="true"></span> Todo
    </NavLink>
</div>

NavMenu.razor ファイルを保存します。

TodoList フォルダーからコマンド シェルで dotnet watch run コマンドを実行して、アプリをビルドして実行します。 アプリが実行された後、そのアプリのナビゲーション バーにある [Todo] リンクを選択して、新しい Todo ページにアクセスします。これにより、/todo にページが読み込まれます。

アプリでコマンド シェルを実行したままにします。 ファイルが保存されるたび、アプリは自動的にリビルドされ、ブラウザーのページは自動的に再度読み込まれます。

Todo アイテムを表すクラスを保持するために、プロジェクト (TodoList フォルダー) のルートに TodoItem.cs ファイルを追加します。 TodoItem クラス用に次の C# コードを使います。

TodoItem.cs:

namespace BlazorSample;

public class TodoItem
{
    public string? Title { get; set; }
    public bool IsDone { get; set; }
}
public class TodoItem
{
    public string? Title { get; set; }
    public bool IsDone { get; set; }
}
public class TodoItem
{
    public string? Title { get; set; }
    public bool IsDone { get; set; }
}
public class TodoItem
{
    public string Title { get; set; }
    public bool IsDone { get; set; }
}
public class TodoItem
{
    public string Title { get; set; }
    public bool IsDone { get; set; }
}

注意

TodoItem.cs ファイルと TodoItem クラスを作成するために Visual Studio を使用している場合は、次の "いずれか" の方法を使用します。

  • Visual Studio によってクラス用に生成される名前空間を削除します。
  • 前のコード ブロックの [コピー] ボタンを使用し、Visual Studio によって生成されるファイルの内容全体を置き換えます。

Todo コンポーネントに戻り、次のタスクを実行します。

  • Todo アイテム用のフィールドを @code ブロックに追加します。 Todo コンポーネントでは、このフィールドを使って ToDo リストの状態を維持します。
  • 各 Todo アイテムをリスト アイテム (<li>) としてレンダリングするために、順序のないリストのマークアップと foreach ループを追加します。

Components/Pages/Todo.razor:

@page "/todo"
@rendermode InteractiveServer

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

@code {
    private List<TodoItem> todos = new();
}

Pages/Todo.razor:

@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

@code {
    private List<TodoItem> todos = new();
}

Pages/Todo.razor:

@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

@code {
    private List<TodoItem> todos = new();
}

Pages/Todo.razor:

@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

@code {
    private List<TodoItem> todos = new();
}

Pages/Todo.razor:

@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();
}

アプリには、リストに Todo 項目を追加するための UI 要素が必要です。 順序のないリスト (<ul>...</ul>) の下に、テキスト入力 (<input>) とボタン (<button>) を追加します。

@page "/todo"
@rendermode InteractiveServer

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" />
<button>Add todo</button>

@code {
    private List<TodoItem> todos = new();
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" />
<button>Add todo</button>

@code {
    private List<TodoItem> todos = new();
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" />
<button>Add todo</button>

@code {
    private List<TodoItem> todos = new();
}
@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" />
<button>Add todo</button>

@code {
    private List<TodoItem> todos = new();
}
@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" />
<button>Add todo</button>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();
}

TodoItem.cs ファイルと更新された Todo.razor ファイルを保存します。 コマンド シェルでは、ファイルが保存されるとアプリが自動的に再構築されます。 ブラウザーによってページが再度読み込まれます。

Add todo ボタンを選択しても何も起こりません。ボタンにイベント ハンドラーがアタッチされていないためです。

Todo コンポーネントに AddTodo メソッドを追加し、@onclick 属性を使用して、そのメソッドをボタン用に登録します。 ボタンを選択すると C# のメソッド AddTodo が呼び出されます。

<input placeholder="Something todo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        // Todo: Add the todo
    }
}
<input placeholder="Something todo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        // Todo: Add the todo
    }
}
<input placeholder="Something todo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        // Todo: Add the todo
    }
}
<input placeholder="Something todo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();

    private void AddTodo()
    {
        // Todo: Add the todo
    }
}
<input placeholder="Something todo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();

    private void AddTodo()
    {
        // Todo: Add the todo
    }
}

新しい Todo アイテムのタイトルを取得するには、@code ブロックの先頭に newTodo 文字列フィールドを追加します。

private string? newTodo;
private string newTodo;

@bind 属性を使用して newTodo をバインドするようにテキストの <input> 要素を変更します。

<input placeholder="Something todo" @bind="newTodo" />

指定したタイトルを備えた TodoItem をリストに追加するように、AddTodo メソッドを更新します。 newTodo を空の文字列に設定して、テキスト入力の値をクリアします。

@page "/todo"
@rendermode InteractiveServer

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<h3>Todo</h3>

<ul>
    @foreach (var todo in todos)
    {
        <li>@todo.Title</li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private IList<TodoItem> todos = new List<TodoItem>();
    private string newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}

Todo.razor ファイルを保存します。 アプリはコマンド シェルで自動的にリビルドされ、ページはブラウザーで再度読み込まれます。

各 Todo アイテムのタイトルのテキストは編集可能にすることができます。また、チェックボックスはユーザーが完了したアイテムを追跡するのに役立ちます。 各 Todo アイテムにチェックボックス入力を追加し、その値を IsDone プロパティにバインドします。 @todo.Title を、@bindtodo.Title にバインドされた <input> 要素に変更します。

<ul>
      @foreach (var todo in todos)
      {
         <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
         </li>
      }
</ul>

<h3> ヘッダーを更新し、完了していない (IsDonefalse の) Todo アイテムの数のカウントを表示するようにします。 次のヘッダーの Razor 式は、Blazor がコンポーネントを再レンダリングするたびに評価されます。

<h3>Todo (@todos.Count(todo => !todo.IsDone))</h3>

完成した Todo コンポーネント:

@page "/todo"
@rendermode InteractiveServer

<PageTitle>Todo</PageTitle>

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<PageTitle>Todo</PageTitle>

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}
@page "/todo"

<h1>Todo (@todos.Count(todo => !todo.IsDone))</h1>

<ul>
    @foreach (var todo in todos)
    {
        <li>
            <input type="checkbox" @bind="todo.IsDone" />
            <input @bind="todo.Title" />
        </li>
    }
</ul>

<input placeholder="Something todo" @bind="newTodo" />
<button @onclick="AddTodo">Add todo</button>

@code {
    private List<TodoItem> todos = new();
    private string? newTodo;

    private void AddTodo()
    {
        if (!string.IsNullOrWhiteSpace(newTodo))
        {
            todos.Add(new TodoItem { Title = newTodo });
            newTodo = string.Empty;
        }
    }
}

Todo.razor ファイルを保存します。 アプリはコマンド シェルで自動的にリビルドされ、ページはブラウザーで再度読み込まれます。

アイテムを追加し、アイテムを編集し、Todo アイテムに完了のマークを付けて、コンポーネントをテストします。

完了したら、コマンド シェルでアプリをシャットダウンします。 多くのコマンド シェルでは、Ctrl+C (Windows) または +C (macOS) キーボード コマンドを使用してアプリを停止できます。

Azure に発行する

Azure へのデプロイについては、「クイックスタート: ASP.NET Web アプリをデプロイする」を参照してください。

次のステップ

このチュートリアルでは、次の作業を行う方法を学びました。

  • Todo リストの Blazor アプリ プロジェクトを作成する
  • Razor コンポーネントを変更する
  • コンポーネントでイベント処理とデータ バインディングを使用する
  • Blazor アプリでルーティングを使用する

ASP.NET Core Blazor 用のツールについて学習します。