MVVM: Create some processings if these should execute before adding to a list items.

When you provide any list, it’s items would not enough for user, not always. Accordingly, a ComboBox control is provided for developers. However, I want to include some processings before adding to list items occasionally. So, I use a ListBox( or ListView) control and a TextBox contorol with a Button control.
This article describes these synchronization.

Sample solution

・Create Visual Studio Solution of MVVM design pattern type

First, create visual studio solution from template of blank universal app (c#). And then, create class files in the shared project as a model( Artist model) and a view model( MainPage view model), a facade( Data access layer). See below.

・Create XAML page

Next, create XAML codes of a ListView control and a TextBox control, a Button control.

<ListView x:Name="ArtistListView" Grid.Row="1" Grid.ColumnSpan="2"
    Margin="100,10,100,0" BorderBrush="White" BorderThickness="1"
    Header="Artist List" ItemsSource="{Binding ArtistListViewItemsSource}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding FirstName}"/>
                <TextBlock Text="{Binding LastName}" Margin="10,0,0,0"/>
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
<StackPanel Grid.Row="2" VerticalAlignment="Center" >
    <TextBlock
        Text="Separate by a space between firstname and lastname, if necessary."
        HorizontalAlignment="Right"/>
    <TextBox x:Name="AddContent" Text="{Binding AddContentText,Mode=TwoWay}"
        Width="300" Height="50" HorizontalAlignment="Right"
        PlaceholderText="Enter if it is not in the list."/>
</StackPanel>
<Button x:Name="AddToListButton" Content="Add to the list" Margin="10,0,0,0"
    Grid.Row="2" Grid.Column="1" Command="{Binding AddToListButtonCommand}" />

・Create View Model

A mechanism of those controls relaying each other is that a Command property of a Button control sets a Text property of a TextBox control to a ItemsSource property of a ListView. ICommand type property in this view model is extended by custom type that has “public Action ExecuteAction {get;set;}” property. This is a view model codes below.

class addToListCommand : ICommand
{
    // extends this property
    public Action ExecuteAction {get;set;}
    public bool CanExecute(object parameter) { return true; }
    public event EventHandler CanExecuteChanged;
    public void Execute(object parameter) { ExecuteAction(); }
}
addToListCommand addToListButtonCommand { get; set; }
// bind to a Command property of the Button
public ICommand AddToListButtonCommand
{
    get
    {
        if (addToListButtonCommand == null)
        {
            addToListButtonCommand = new addToListCommand();
            // This "AddContentText" is a property of the TextBox control.
            addToListButtonCommand.ExecuteAction
                = () => AddToArtistList(AddContentText);
        }
        return addToListButtonCommand;
    }
}

The command executes “AddToArtistList(AddContentText);” setted from external code via the ExecuteAction property. “AddContentText” argument is a property binding to a Text property of the TextBox. And “AddToArtistList” method do the process that separates a string given to two or three strings as first name or last name. The view model codes is below.

public ObservableCollection<ArtistModel> ArtistListViewItemsSource
    { get; private set; }
public void AddToArtistList(string name)
{
    artistModel = new ArtistModel();
    string[] names = name.Split(' ');
    artistModel.FirstName = names[0];
    if (names.Length > 1) artistModel.LastName = names[names.Length - 1];
    if (!string.IsNullOrEmpty(artistModel.FirstName))
    {
        ArtistListViewItemsSource.Add(artistModel);
        RaisePropertyChanged("ArtistListViewItemsSource");
    }
}

・Windows 8.1 or later

An information inputted by user on button operation add to the list. It is easier to create on the platform as Windows 8.1 or later.

<Button x:Name="AddToListFromFlyoutButton"
    Content="Enter if it is not in the list" HorizontalAlignment="Center"
    Margin="0,50,0,0">
    <Button.Flyout>
        <Flyout>
            <StackPanel>
                <StackPanel Orientation="Horizontal">
                    <TextBox Header="First Name"
                        Text="{Binding FirstNameTextBoxText, Mode=TwoWay,
                        UpdateSourceTrigger=PropertyChanged}" Width="100"/>
                    <TextBox Header="Last Name"
                        Text="{Binding LastNameTextBoxText, Mode=TwoWay,
                        UpdateSourceTrigger=PropertyChanged}" Width="100"
                        Margin="10,0,0,0"/>
                </StackPanel>
                <Button x:Name="ListContentAddingButton"
                    Content="{Binding ListContentAddingButtonContent}"
                    HorizontalAlignment="Right" Margin="0,10,0,0"
                    Click="ListContentAddingButtonContent_Click"
                    IsEnabled="{Binding ListContentAddingButtonIsEnabled}"/>
            </StackPanel>
        </Flyout>
    </Button.Flyout>
</Button>

A name input area is able to divide first name and last name using a Flyout control. And a IsEnabled property or a Content property of a Button control is able to change per inputting a character to a TextBox control because a Binding.UpdateSourceTrigger property of it execute setter method of the property that change a IsEnabled property or a Content property of a Button control.

Consequently, create a process on a click event handler that closing a Flyout control and calling “AddToArtistList” method in the view model.

private void ListContentAddingButtonContent_Click(object sender, RoutedEventArgs e)
{
    Flyout f = this.AddToListFromFlyoutButton.Flyout as Flyout;
    if(f != null) f.Hide();
    (DataContext as MainPageViewModel).AddToArtistList(null);
}

Modify “AddToArtistList” method in the view model to a code below.

string firstNameTextBoxText { get; set; }
public string FirstNameTextBoxText
{
    get
    {
        return firstNameTextBoxText;
    }
    set
    {
        firstNameTextBoxText = value;
        RaisePropertyChanged("ListContentAddingButtonContent");
        RaisePropertyChanged("ListContentAddingButtonIsEnabled");
    }
}
string lastNameTextBoxText { get; set; }
public string LastNameTextBoxText
{
    get
    {
        return lastNameTextBoxText;
    }
    set
    {
        lastNameTextBoxText = value;
        RaisePropertyChanged("ListContentAddingButtonContent");
    }
}
public string ListContentAddingButtonContent
{
    get
    {
        string result = "O K";
        if (!string.IsNullOrEmpty(FirstNameTextBoxText))
        {
            result += ": " + FirstNameTextBoxText;
            if (!string.IsNullOrEmpty(LastNameTextBoxText))
                result += " " + LastNameTextBoxText;
        }
        return result;
    }
}
public bool ListContentAddingButtonIsEnabled
{
    get { return (!string.IsNullOrEmpty(FirstNameTextBoxText)); }
}

public void AddToArtistList(string name)
{
    artistModel = new ArtistModel();
    if (!string.IsNullOrEmpty(FirstNameTextBoxText))
    {
        artistModel.FirstName = FirstNameTextBoxText;
        if (!string.IsNullOrEmpty(LastNameTextBoxText))
            artistModel.LastName = LastNameTextBoxText;
    }
    if (!string.IsNullOrEmpty(artistModel.FirstName))
    {
        ArtistListViewItemsSource.Add(artistModel);
        RaisePropertyChanged("ArtistListViewItemsSource");
    }
    //Serialize and save to local. Refer to sample code about Dal.
    Dal.SetLocalArtistsData(ArtistListViewItemsSource);
}

About takao

I'm Microsoft MVP since June 2010.