0
votes

I am trying to bind checkbox as below but when I click on it it doesn't even stay checked.Below is my model that maps to the db.I would like to get selected item using the checked checkboxes so I can eventually grab the cost fields.I have attempted to follow the code example from Programming Windows Store Apps with C#. by Matt Baxter-Reynolds and Iris Classon.I have updated my code to match answer provided by @Arnaud.The checkbox doesn't stay checked but the visibility of the button changes on clicking on the radiobuttons.

Model ServiceItem

     public class ServiceItem:ModelItem
    {
        // key field...
        [AutoIncrement(), PrimaryKey(), JsonIgnore]
        public int Id { get; set; }

        // other fields...
        [Unique, JsonProperty("id")]
        public int NativeId { get; set; }
        [JsonProperty("name")]
        public string Name { get; set; }
        public decimal Cost
      {
        get
        {
            return GetValue<decimal>();
        }
        set
        {
            SetValue(value);
        }
      }
      [JsonIgnore] //prefer not to have it on db has no value
      public bool IsSelected
     {
        get
        {
            return GetValue<bool>();
        }
        set
        {
            SetValue(value);
        }
     }

        public ServiceItem()
        {
        }
    }

Below is the Viewmodel

ServicesPage ViewModel

    public class ServicesPageViewModel : ViewModel, IServicesPageViewModel
{
    public ObservableCollection<ServiceItem> Items { get; private set; }

    public ICommand ContinueCommand { get; private set; }
    public ServicesPageViewModel()
    {
    }

    public override void Initialize(IViewModelHost host)
    {
        base.Initialize(host);
        // setup...
        this.Items = new ObservableCollection<ServiceItem>();

        this.ContinueCommand = new DelegateCommand((args) => GetSelected(args as CommandExecutionContext));

    }

}

Below is the xaml ServicePage.xaml

<ListView ItemsSource="{Binding Items}" 
                  IsItemClickEnabled="true"                      
                  Margin="10,10,10,0" TabIndex="1">                
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="3*"></ColumnDefinition>
                            <ColumnDefinition/>
                        </Grid.ColumnDefinitions>
                        <CheckBox Content="{Binding Name}"  
                                  BorderBrush="{ThemeResource AppBarBackgroundThemeBrush}"
                                  IsChecked="{Binding IsSelected, Mode=TwoWay}"></CheckBox>
                        <Button Content="{Binding Cost, Mode=TwoWay}" 

Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Column="1">

Viewmodel

public abstract class ViewModel : ModelItem, IViewModel
    {
        //  somewhere to hold the host...
        protected IViewModelHost Host { get; private set; }
    //other code omitted
    }

Viewmodel interface Iviewmodel

 public interface IViewModel : INotifyPropertyChanged
    {
        void Initialize(IViewModelHost host);
    //other code omitted
    }

ModelItem

public abstract class ModelItem : INotifyPropertyChanged
{
    private Dictionary<string, object> Values { get; set; }

    protected ModelItem()
    {
        this.Values = new Dictionary<string, object>();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected T GetValue<T>([CallerMemberName] string name = null)
    {
        if (this.Values.ContainsKey(name))
            return (T)this.Values[name];
        else
            return default(T);
    }

    protected void SetValue(object value, [CallerMemberName] string name = null)
    {
        // set...
        this.Values[name] = value;

        // notify...
        this.OnPropertyChanged(new PropertyChangedEventArgs(name));
    }

    protected void OnPropertyChanged([CallerMemberName] string name = null)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(name));
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, e);
    }
}
1

1 Answers

3
votes

you need to implement INotifyPropertyChanged on your class ServiceItem otherwise you will never raise any event when the value is updated.

Here is the code of my view. I have added a converter to display the cost only when items are selected:

<Page
    x:Class="App4.CheckBoxPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App4"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    >
    <Page.Resources>
        <local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </Page.Resources>
    <ListView ItemsSource="{Binding Items}" 
                  IsItemClickEnabled="true"                      
                  Margin="10,10,10,0" TabIndex="1">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="3*"></ColumnDefinition>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <CheckBox Content="{Binding Name}"  
                                  BorderBrush="{ThemeResource AppBarBackgroundThemeBrush}"
                                  IsChecked="{Binding IsSelected, Mode=TwoWay}"></CheckBox>
                    <Button Content="{Binding Cost, Mode=TwoWay}" Visibility="{Binding IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}" Grid.Column="1"></Button>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Page>

And the classes, I have used. ServiceItem needs to extend ModelItem so as to notify the view of changes on properties Cost and IsSelected. Without it, the View will only get the initial values of Cost and IsSelected and all updates on these properties will be ignored by the View.

public sealed partial class CheckBoxPage : Page
{
    public CheckBoxPage()
    {
        var items = new ObservableCollection<ServiceItem>()
        {
            new ServiceItem() {Name = "Item 1", Id = 1, NativeId = 1, Cost = 123 },
            new ServiceItem() {Name = "Item 2", Id = 2, NativeId = 2, Cost = 456 },
            new ServiceItem() {Name = "Item 3", Id = 3, NativeId = 3, Cost = 789 },
            new ServiceItem() {Name = "Item 4", Id = 4, NativeId = 4, Cost = 1011 },
        };

        Items = items;

        this.InitializeComponent();
    }

    public ObservableCollection<ServiceItem> Items
    {
        get;
        set;
    }
}

public class ServiceItem : ModelItem
{
    public int Id { get; set; }
    public int NativeId { get; set; }
    public string Name { get; set; }

    public decimal Cost {
        get
        {
            return GetValue<decimal>();
        }
        set
        {
            SetValue(value);
        }
    }

    public bool IsSelected
    {
        get
        {
            return GetValue<bool>();
        }
        set
        {
            SetValue(value);
        }
    }
}