在列表视图 MVVM 中绑定复选框
Bind checkboxes in listview MVVM
我正在尝试如下绑定复选框,但是当我点击它时它甚至不会停留 checked.Below 是我映射到 db.I 的模型想使用选中复选框,以便我最终可以获取成本 fields.I 已尝试遵循 Programming Windows Store Apps with C#. 中的代码示例
作者:Matt Baxter-Reynolds 和 Iris Classon.I 已更新我的代码以匹配@Arnaud.The 提供的答案复选框未保持选中状态但单击单选按钮时按钮的可见性发生变化。
模型服务项
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()
{
}
}
下面是视图模型
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));
}
}
下面是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">
视图模型
public abstract class ViewModel : ModelItem, IViewModel
{
// somewhere to hold the host...
protected IViewModelHost Host { get; private set; }
//other code omitted
}
Viewmodel接口Iviewmodel
public interface IViewModel : INotifyPropertyChanged
{
void Initialize(IViewModelHost host);
//other code omitted
}
模型项目
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);
}
}
您需要在 class ServiceItem
上实施 INotifyPropertyChanged
否则您将永远不会在更新值时引发任何事件。
下面是我的视图代码。我添加了一个转换器以仅在选择项目时显示成本:
<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>
还有classes,我用过。 ServiceItem
需要扩展 ModelItem
以便通知视图属性 Cost 和 IsSelected 的更改。没有它,View 将仅获得 Cost 和 IsSelected 的初始值,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);
}
}
}
我正在尝试如下绑定复选框,但是当我点击它时它甚至不会停留 checked.Below 是我映射到 db.I 的模型想使用选中复选框,以便我最终可以获取成本 fields.I 已尝试遵循 Programming Windows Store Apps with C#. 中的代码示例 作者:Matt Baxter-Reynolds 和 Iris Classon.I 已更新我的代码以匹配@Arnaud.The 提供的答案复选框未保持选中状态但单击单选按钮时按钮的可见性发生变化。
模型服务项
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()
{
}
}
下面是视图模型
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));
}
}
下面是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">
视图模型
public abstract class ViewModel : ModelItem, IViewModel
{
// somewhere to hold the host...
protected IViewModelHost Host { get; private set; }
//other code omitted
}
Viewmodel接口Iviewmodel
public interface IViewModel : INotifyPropertyChanged
{
void Initialize(IViewModelHost host);
//other code omitted
}
模型项目
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);
}
}
您需要在 class ServiceItem
上实施 INotifyPropertyChanged
否则您将永远不会在更新值时引发任何事件。
下面是我的视图代码。我添加了一个转换器以仅在选择项目时显示成本:
<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>
还有classes,我用过。 ServiceItem
需要扩展 ModelItem
以便通知视图属性 Cost 和 IsSelected 的更改。没有它,View 将仅获得 Cost 和 IsSelected 的初始值,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);
}
}
}