XAML 在WPF表单中使用MVVM返回绑定复选框值

xggvc2p6  于 2022-12-07  发布在  其他
关注(0)|答案(2)|浏览(167)

我有一个由字符串和数组组成的对象。字符串填充ComboBox,数组填充ListView,这取决于所选的字符串值。ListView的每一行都由TextBlockCheckBox组成。
在提交时,我希望能够验证哪些项已被选中进行进一步处理,但在使用MVVM方法时会出现中断。我目前将提交ButtonDataContext绑定到ListView,但在提交时只返回第一个值(我需要将选定的值保存到一个列表中,我假设是这样,但我不确定保存在哪里)。我向模型添加了一个IsSelected属性,我认为这是第一步,但之后我一直在抓救命稻草。
型号

namespace DataBinding_WPF.Model
{
    public class ExampleModel { }

    public class Example : INotifyPropertyChanged
    {
        private string _name;
        private string[] _ids;
        private bool _isSelected;

        public bool IsSelected
        {
            get => _isSelected;
            set
            {
                if (_isSelected != value)
                {
                    _isSelected = value;
                    RaisePropertyChanged("IsSelected");
                }
            }
        }

        public string Name
        {
            get => _name;
            set
            {
                if (_name != value)
                {
                    _name = value;
                    RaisePropertyChanged("Name");
                }
            }
        }

        public string[] IDs
        {
            get => _ids;
            set
            {
                if (_ids != value)
                {
                    _ids = value;
                    RaisePropertyChanged("IDs");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new 
                    PropertyChangedEventArgs(property));
            }
        }
    }
}

检视模型

namespace DataBinding_WPF.ViewModel
{
    public class ExampleViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<Example> Examples
        {
            get;
            set;
        }

        // SelectedItem in the ComboBox
        // SelectedItem.Ids will be ItemsSource for the ListBox
        private Example _selectedItem;
        public Example SelectedItem
        {
            get => _selectedItem;
            set
            {
                _selectedItem = value;
                RaisePropertyChanged(nameof(SelectedItem));
            }
        }

        // SelectedId in ListView
        private string _selectedId;
        public string SelectedId
        {
            get => _selectedId;
            set
            {
                _selectedId = value;
                RaisePropertyChanged(nameof(SelectedId));
            }
        }

        private string _selectedCheckBox;
        public string IsSelected
        {
            get => _selectedCheckBox;
            set
            {
                _selectedCheckBox = value;
                RaisePropertyChanged(nameof(IsSelected));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new
                    PropertyChangedEventArgs(property));
            }
        }

        public void LoadExample()  
        {
            ObservableCollection<Example> examples = new ObservableCollection<Example>();
            examples.Add(new Example { Name = "Mark", IDs = new string[] { "123", "456" }, IsSelected = false });
            examples.Add(new Example { Name = "Sally", IDs = new string[] { "789", "101112" }, IsSelected = false });
            Examples = examples;
        }

        /* BELOW IS A SNIPPET I ADDED FROM AN EXAMPLE I FOUND ONLINE BUT NOT SURE IF IT'S NEEDED */
        private ObservableCollection<Example> _bindCheckBox;
        public ObservableCollection<Example> BindingCheckBox
        {
            get => _bindCheckBox;
            set
            {
                _bindCheckBox = value;
                RaisePropertyChanged("BindingCheckBox");
            }
        }
    }
}

检视

<UserControl x:Class = "DataBinding_WPF.Views.StudentView" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" 
   xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" 
   xmlns:local = "clr-namespace:DataBinding_WPF" 
   mc:Ignorable = "d" 
   d:DesignHeight = "300" d:DesignWidth = "300">

    <Grid>
        <StackPanel HorizontalAlignment = "Left" >

            <ComboBox HorizontalAlignment="Left"   
                  VerticalAlignment="Top"   
                  Width="120"   
                  ItemsSource="{Binding Path=Examples}"    
                  SelectedItem="{Binding SelectedItem}"  
                  DisplayMemberPath="Name"/>

            <ListView x:Name="myListView" 
                        ItemsSource="{Binding SelectedItem.IDs}"
                        DataContext="{Binding DataContext, ElementName=submit_btn}"
                        SelectedItem="{Binding SelectedId}" 
                        Height="200" Margin="10,50,0,0" 
                              Width="Auto"
                        VerticalAlignment="Top"
                        Background="AliceBlue">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" >
                            <CheckBox 
                                    Name="myCheckBox"                            
                                    IsChecked="{Binding IsSelected,
                                        RelativeSource={RelativeSource AncestorType=ListViewItem}}"
                                        Margin="5, 0"/>
                            <TextBlock Text="{Binding}" FontWeight="Bold" />
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

            <Button HorizontalAlignment="Left" Height="20" Width="100"
                    Click="Submit" x:Name="submit_btn">Submit</Button>
        </StackPanel>
    </Grid>
</UserControl>

View.cs

namespace DataBinding_WPF.Views
{
    /// <summary>
    /// Interaction logic for StudentView.xaml
    /// </summary>
    public partial class StudentView : UserControl
    {
        public StudentView()
        {
            InitializeComponent();
        }

        private void Submit(object sender, EventArgs e)
        {
            var selectedItems = ((Button)sender).DataContext;

            // process each selected item
           // foreach (var selected in ....) { }
        }
    }
}
0kjbasz6

0kjbasz61#

ListView控件已将选定项集合公开为属性SelectedItems

private void Submit(object sender, RoutedEventArgs e)
{
   var selectedIds = myListView.SelectedItems.Cast<string>().ToList();
   // ...do something with the items.
}

但是,我怀疑您是否希望在代码隐藏中执行此操作,而是希望在视图模型中执行此操作。

您需要的是中继命令或委派命令(名称因框架而异)。它封装了一个应该执行的方法(例如,单击按钮)和一个确定命令是否可以作为可以绑定到视图中的对象执行的方法。遗憾的是,WPF没有提供现成的实现,因此您要么必须复制here之类的实现,要么使用已经提供了一个实现的MVVM框架,例如Microsoft MVVM Tookit
您可以在ExampleViewModel中公开ICommand型别的属性Submit,并在建构函式中以委派给要执行之方法的RelayCommand<T>执行严修初始化它。

public class ExampleViewModel : INotifyPropertyChanged
{
   public ExampleViewModel()
   {
      Submit = new RelayCommand<IList>(ExecuteSubmit);
   }

   public RelayCommand<IList> Submit { get; }

   // ...other code.

   private void ExecuteSubmit(IList selectedItems)
   {
      // ...do something with the items.
      var selectedIds = selectedItems.Cast<string>().ToList();
      return;
   }
}

在您的视图中,可以删除Click事件处理程序,并将Submit属性绑定到ButtonCommand属性。还可以将ListViewSelectedItems属性绑定到CommandParameter属性,以便在执行时将选定项传递给命令。

<Button HorizontalAlignment="Left"
        Height="20"
        Width="100"
        x:Name="submit_btn"
        Command="{Binding Submit}"
        CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>

此外,还有一些关于XAML的说明。

  • XAML中的控件名称应该是Pascal-Case,以大写字母开头。
  • 您应该从ListView中完全删除DataContext绑定,因为它无论如何都会自动接收与Button相同的数据上下文。
DataContext="{Binding DataContext, ElementName=submit_btn}"
<Grid>
   <StackPanel HorizontalAlignment = "Left" >

      <ComboBox HorizontalAlignment="Left"   
                VerticalAlignment="Top"   
                Width="120"   
                ItemsSource="{Binding Path=Examples}"   
                IsSynchronizedWithCurrentItem="True"
                DisplayMemberPath="Name"/>

      <ListView ItemsSource="{Binding Examples/IDs}"
                SelectedItem="{Binding SelectedId}" 
                Height="200" Margin="10,50,0,0" 
                Width="Auto"
                VerticalAlignment="Top"
                Background="AliceBlue">
         <ListView.ItemTemplate>
            <DataTemplate>
               <StackPanel Orientation="Horizontal" >
                  <CheckBox Name="myCheckBox"                            
                            IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}"
                            Margin="5, 0"/>
                  <TextBlock Text="{Binding}"
                             FontWeight="Bold" />
               </StackPanel>
            </DataTemplate>
         </ListView.ItemTemplate>
      </ListView>

      <Button HorizontalAlignment="Left"
              Height="20"
              Width="100"
              Command="{Binding Submit}"
              CommandParameter="{Binding SelectedItems, ElementName=myListView}">Submit</Button>

   </StackPanel>
</Grid>
txu3uszq

txu3uszq2#

如果视图的数据上下文绑定到视图,则从ListView中删除DataContext。
您可以移除项目模板,并改用GridView,例如:

<ListView.View>
      <GridView >
          <GridViewColumn Header="Selected" >
              <GridViewColumn.CellTemplate>
                   <DataTemplate>
                       <CheckBox IsChecked="{Binding IsSelected}" Content="{Binding Name}" />
                   </DataTemplate>
              </GridViewColumn.CellTemplate>
          </GridViewColumn>
    </GridView>
</ListView.View>

由于ItemSource是一个可观察的集合,因此在复选框中有几个用于监视更改的选项:
1.将事件处理程序添加到集合的item changed事件,然后可以将Name或集合索引添加到本地集合。例如Examples[e.CollectionIndex].Name
1.或者,迭代可观察集合并选择Selected =“true”的那些示例

相关问题