kontable
kontable

Reputation: 73

MVVM populating a combobox (WinRT and C#)

I have a ComboBox in my XAML. It is populated with the following code:

PopulateColors.cs

public class PopulateColors
{
    public ObservableCollection<ItemsColors> itemsColors { get; set; } 

    public PopulateColors()
    {
        this.itemsColors = new ObservableCollection<ItemsColors>();
        this.itemsColors.Add(new ItemsColors{ ItemColumn = "Blue", IdItemColumn = 0 });      
        this.itemsColors.Add(new ItemsColors{ ItemColumn = "Red", IdItemColumn = 1 }); 
        this.itemsColors.Add(new ItemsColors{ ItemColumn = "Pink", IdItemColumn = 2 });        
    }      
}

public class ItemsColors
{
    public string ItemColumn { get; set; }
    public int IdItemColumn { get; set; }
}

pagedemo.xaml.cs:

ClothingViewModel  ClothVM = null;

public pagedemo()
{
    this.comboColors.DataContext = new PopulateColors();
} 

protected override void OnNavigatedTo(NavigationEventArgs e)
{           
    ClothVM  = new   ClothingViewModel();
    ClothVM  =  ClothVM.GetData(1);
    this.DataContext =  ClothVM ;
    navigationHelper.OnNavigatedTo(e);
}

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
    string result =  ClothVM .Save( ClothVM );
    if (result.Contains("OK"))
    {
        //to do
    }
}

pagedemo.xaml (XAML design)

<TextBox x:Name="txtJersey" 
         Text="{Binding Jersey, Mode=TwoWay}"/>

<ComboBox Name="comboColors"
          ItemsSource="{Binding itemsColors}"
          DisplayMemberPath="ItemColumn"                                                 
          SelectedValuePath="ItemColumn"/>  

Ok. items are display fine in ComboBox.

QUESTION:

I need to save the selected color in a table of the database, using MVVM pattern. But how? I have this code. But I do not know how to link it with the ComboBox:

Model: Clothing.cs

Public class Clothing
{
    public string Color { get; set; }
    public string Jersey { get; set; }
}

ViewModel: ClothingViewModel.cs

public class ClothingViewModel : ViewModelBase
{ 
    public string Save (ClothingViewModel cloth)
    {
        string result = string.Empty;
        using (var db = new SQLite.SQLiteConnection(App.DBPath))
        {
            string change = string.Empty;
            try
            {
                var existing = (db.Table<Clothing>().Where(
                    c => c.id == 1)).SingleOrDefault();
                if (existing!= null)
                {
                    existing.Color = cloth.Color;
                    existing.Jersey = cloth.Jersey;
                    int success = db.Update(existing);
                }                 
            }
            catch
            { }
        }       
    }

    private int id = 1;
    public int ID
    {
        get
        { return id; }
        set
        {
            if (id == value)
            { return; }
            id= value;                
            RaisePropertyChanged("ID");
        }
    }

    private string color = string.Empty;
    public string Color
    {
        get
        { return color; }
        set
        {
            if (color == value)
            { return; }
            color = value;
            isDirty = true;
            RaisePropertyChanged("Color");
        }
    }

    private string jersey = string.Empty;
    public string Jersey
    {
        get
        { return jersey; }
        set
        {
            if (jersey == value)
            { return; }
            jersey = value;
            isDirty = true;
            RaisePropertyChanged("Jersey");
        }
    }
}

Upvotes: 2

Views: 739

Answers (1)

Actually, there are plenty of options. Let's demonstrate just a few of them.

1. Use Binding with RelativeSource to find Ancestor with appropriate DataContext

XAML-code:

<!-- Please use Page instead of Window. -->
<Window>
    <StackPanel>
        <TextBox x:Name="txtJersey" 
                 Text="{Binding Jersey, Mode=TwoWay}"/>

        <!-- Use {x:Type Page} instead of {x:Type Window}. -->
        <ComboBox Name="comboColors" ItemsSource="{Binding itemsColors}"
                  DisplayMemberPath="ItemColumn"
                  SelectedValue="{Binding 
                      RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}},
                      Path=DataContext.Color}"
                  SelectedValuePath="ItemColumn" />
    </StackPanel>
</Window>

2. Use Binding with ElementName to the UI-element with appropriate DataContext

XAML-code:

<StackPanel>
    <TextBox x:Name="txtJersey" 
             Text="{Binding Jersey, Mode=TwoWay}"/>

    <ComboBox Name="comboColors" ItemsSource="{Binding itemsColors}"
              DisplayMemberPath="ItemColumn"
              SelectedValue="{Binding 
                  ElementName=txtJersey,
                  Path=DataContext.Color}"
              SelectedValuePath="ItemColumn" />
</StackPanel>

3. Use "one" ViewModel that contains another ViewModel

public class ClothingViewModel : ViewModelBase
{
    private readonly PopulateColors colors = new PopulateColors();

    public PopulateColors Colors
    {
        get { return this.colors; }
    }

    ...
}

Page:

// This is a Page (Window in case of using WPF).
public class ClothingWindow
{
    public ClothingWindow()
    {
        InitializeComponent();
        // Note: no need to set the DataContext for the ComboBox.
        DataContext = new ClothingViewModel();
    }
}

XAML-code:

<StackPanel>
    <TextBox Text="{Binding Jersey, Mode=TwoWay}"/>
    <ComboBox ItemsSource="{Binding Colors.itemsColors}"
              DisplayMemberPath="ItemColumn"
              SelectedValue="{Binding Color}"
              SelectedValuePath="ItemColumn" />
</StackPanel>

References

  1. Data Binding (WPF), MSDN.
  2. Data Binding in WPF, John Papa, MSDN Magazine.

Upvotes: 2

Related Questions