Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/268.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Datagrid wpf c#应用程序中的复选框_C#_Wpf_Datagrid - Fatal编程技术网

Datagrid wpf c#应用程序中的复选框

Datagrid wpf c#应用程序中的复选框,c#,wpf,datagrid,C#,Wpf,Datagrid,我正在使用datagrid为学生记录创建一个C#wpf应用程序。 如何在标题中创建复选框以选中/取消选中行中的所有复选框? 如何单击选中行中的复选框,以便编辑/删除记录?以及我们如何选择多个要删除的复选框 使用这样的东西: DataGridCheckBoxColumn cbc = new DataGridCheckBoxColumn(); dataGrid.Columns.Add(cbc); CheckBox cb = new CheckBox(); cbc.Header = cb; <

我正在使用datagrid为学生记录创建一个C#wpf应用程序。 如何在标题中创建复选框以选中/取消选中行中的所有复选框? 如何单击选中行中的复选框,以便编辑/删除记录?以及我们如何选择多个要删除的复选框

使用这样的东西:

DataGridCheckBoxColumn cbc = new DataGridCheckBoxColumn();
dataGrid.Columns.Add(cbc);
CheckBox cb = new CheckBox();
cbc.Header = cb;
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" x:Class="WpfApplication2.MainWindow"
    Title="MainWindow" mc:Ignorable="d" Height="350" Width="525">
<Window.Resources>
    <Style x:Key="DataGridRowStyle" TargetType="{x:Type DataGridRow}">
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
    </Style>
</Window.Resources>
<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>
<Grid>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}" CanUserAddRows="False" RowStyle="{DynamicResource DataGridRowStyle}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Binding="{Binding IsSelected}">
                <DataGridCheckBoxColumn.Header>
                    <CheckBox>
                        <i:Interaction.Behaviors>
                            <local:CollectionPropertyBehavior CollectionPropertyPath="IsSelected" SourcePropertyPath="IsChecked" ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                        </i:Interaction.Behaviors>
                    </CheckBox>                                 
                </DataGridCheckBoxColumn.Header>            
            </DataGridCheckBoxColumn>
            <DataGridTextColumn Width="*" Binding="{Binding MyProperty}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>
并处理
选中的
未选中的
事件:

cb.Checked+=new RoutedEventHandler(cb_Checked); 
cb.Unchecked+=new RoutedEventHandler(cb_Unchecked);

我创建了一种行为,允许控件中的属性绑定到项集合的属性,其方式如下:

  • 如果更改控件中的属性,则会更新所有项
  • 如果更改项目中的属性,如果所有项目都具有相同的属性,则控件将反映该属性。如果不是,控件的属性将被赋予一个回退值(如null)
通过此行为,您可以向DataGrid标头添加复选框,并将其IsChecked属性绑定到DataGrid的ItemSource,以及集合类型的属性

我们可以使用MVVM模式处理选择逻辑。例如,集合实体具有以下ViewModel:

public class ItemViewModel : INotifyPropertyChanged
{
    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    private bool isSelected;
    public bool IsSelected {
        get { return this.isSelected; }

        set
        {
            if (this.isSelected == value)
                return;

            this.isSelected = value;
            this.OnPropertyChanged("IsSelected");
        }
    }

    private string myProperty;
    public string MyProperty
    {
        get { return this.myProperty; }
        set
        {
            if (this.myProperty != value)
            {
                this.myProperty = value;
                this.OnPropertyChanged("MyProperty");
            }
        }
    }
}
然后是MainViewModel,它控制主窗口的逻辑:

public class MainViewModel: INotifyPropertyChanged
{
    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    #region Items (INotifyPropertyChanged Property)
    private ObservableCollection<ItemViewModel> items;

    public ObservableCollection<ItemViewModel> Items
    {
        get { return this.items; }
        set
        {
            if (this.items != value)
            {
                this.items = value;
                this.OnPropertyChanged("Items");
            }
        }
    }
    #endregion

    public MainViewModel()
    {
        this.Items = new ObservableCollection<ItemViewModel>();
        for (int i = 0; i < 10; i++)
            this.Items.Add(new ItemViewModel() { MyProperty = "Item" + i });
    }
}
public类主视图模型:INotifyPropertyChanged
{
#区域inotifyproperty已更改
公共事件属性更改事件处理程序属性更改;
受保护的无效OnPropertyChanged(字符串propertyName)
{
if(this.PropertyChanged!=null)
{
this.PropertyChanged(this,newpropertychangedventargs(propertyName));
}
}
#端区
#区域项(INotifyPropertyChanged属性)
私人可观测收集项目;
公共可观测收集项目
{
获取{返回this.items;}
设置
{
if(this.items!=值)
{
这个项目=价值;
本协议项下的不动产变更(“项目”);
}
}
}
#端区
公共主视图模型()
{
this.Items=新的ObservableCollection();
对于(int i=0;i<10;i++)
this.Items.Add(新的ItemViewModel(){MyProperty=“Item”+i});
}
}
在我们的窗口中,我们可以声明DataGrid。为了实现您的愿望,我们必须做到以下几点:

  • 将MainViewModel分配给Window.DataContext
  • 将DataGrid.ItemsSource绑定到MainViewModel中的Items属性
  • 定义DataGrid的列。在这个示例中,我选择了一个“IsSelected”列,并按照您的指定将“SelectAll”复选框添加到其标题中,但通过该行为,您可以在任何地方都有一个复选框来控制选择
  • 我们需要对行的选择更新项目的“IsSelected”属性,反之亦然。为此,我们修改了RowStyle,以便可以将行的“IsSelected”属性绑定到其项的“IsSelected”。这样,选择逻辑现在可以完全由ViewModel驱动
  • 最后一件事是让“SelectAll”复选框完成它的工作。我们应用CollectionPropertyBehavior并对其进行配置,使其“SourcePropertyPath”指向要绑定的复选框中的属性(“IsChecked”),CollectionPropertyPath指向项中的属性(“IsSelected”)。然后我们只需要将其ItemsSource绑定到DataGridItemsSource。请注意,默认值为“null”,这意味着当项目在其属性中具有不同的值时,复选框将接收“null”并处于未定义状态
最终的xaml如下所示:

DataGridCheckBoxColumn cbc = new DataGridCheckBoxColumn();
dataGrid.Columns.Add(cbc);
CheckBox cb = new CheckBox();
cbc.Header = cb;
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApplication2" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" x:Class="WpfApplication2.MainWindow"
    Title="MainWindow" mc:Ignorable="d" Height="350" Width="525">
<Window.Resources>
    <Style x:Key="DataGridRowStyle" TargetType="{x:Type DataGridRow}">
        <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
    </Style>
</Window.Resources>
<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>
<Grid>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}" CanUserAddRows="False" RowStyle="{DynamicResource DataGridRowStyle}">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Binding="{Binding IsSelected}">
                <DataGridCheckBoxColumn.Header>
                    <CheckBox>
                        <i:Interaction.Behaviors>
                            <local:CollectionPropertyBehavior CollectionPropertyPath="IsSelected" SourcePropertyPath="IsChecked" ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
                        </i:Interaction.Behaviors>
                    </CheckBox>                                 
                </DataGridCheckBoxColumn.Header>            
            </DataGridCheckBoxColumn>
            <DataGridTextColumn Width="*" Binding="{Binding MyProperty}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

最后,行为:

public class CollectionPropertyBehavior : Behavior<DependencyObject>
{
    private IEnumerable<ValueProxy> proxies;
    private bool syncking;

    public string SourcePropertyPath
    {
        get { return (string)GetValue(SourcePropertyPathProperty); }
        set { SetValue(SourcePropertyPathProperty, value); }
    }
    public static readonly DependencyProperty SourcePropertyPathProperty =
        DependencyProperty.Register("SourcePropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));

    public string CollectionPropertyPath
    {
        get { return (string)GetValue(CollectionPropertyPathProperty); }
        set { SetValue(CollectionPropertyPathProperty, value); }
    }
    public static readonly DependencyProperty CollectionPropertyPathProperty =
        DependencyProperty.Register("CollectionPropertyPath", typeof(string), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));


    private IEnumerable<object> Items { get { return  this.ItemsSource == null ? null : this.ItemsSource.OfType<object>(); } }
    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ItemsSourceChanged));


    private object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }
    private static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register("Value", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null, ValueChanged));


    public object DefaultValue
    {
        get { return (object)GetValue(DefaultValueProperty); }
        set { SetValue(DefaultValueProperty, value); }
    }
    public static readonly DependencyProperty DefaultValueProperty =
        DependencyProperty.Register("DefaultValue", typeof(object), typeof(CollectionPropertyBehavior), new PropertyMetadata(null));



    private static void ValueChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;

        element.UpdateCollection();
    }

    private static void ItemsSourceChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as CollectionPropertyBehavior;
        if (element == null || element.ItemsSource == null) return;
        element.ItemsSourceChanged();
    }

    private void ItemsSourceChanged()
    {
        this.proxies = null;

        if (this.Items == null || !this.Items.Any() || this.CollectionPropertyPath == null) return;

        // Cria os proxies
        this.proxies = this.Items.Select(o =>
        {
            var proxy = new ValueProxy();
            proxy.Bind(o, this.CollectionPropertyPath);
            proxy.ValueChanged += (s, e) => this.UpdateSource();
            return proxy;
        }).ToArray();

        this.UpdateSource();
    }

    private void UpdateSource()
    {
        if (this.syncking) return;

        // Atualiza o valor 
        using (new SynckingScope(this))
        {
            object value = this.proxies.First().Value;
            foreach (var proxy in this.proxies.Skip(1))
            {
                value = object.Equals(proxy.Value, value) ? value : this.DefaultValue;
            }

            this.Value = value;
        }
    }

    private void UpdateCollection()
    {
        // Se o valor estiver mudando em função da atualização de algum 
        // elemento da coleção, não faz nada
        if (this.syncking) return;

        using (new SynckingScope(this))
        {
            // Atualiza todos os elementos da coleção,
            // atrávés dos proxies
            if (this.proxies != null)
                foreach (var proxy in this.proxies)
                    proxy.Value = this.Value;
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();


        // Bind da propriedade do objeto fonte para o behavior
        var binding = new Binding(this.SourcePropertyPath);
        binding.Source = this.AssociatedObject;
        binding.Mode = BindingMode.TwoWay;
        BindingOperations.SetBinding(this, ValueProperty, binding);
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();

        // Limpa o binding de value para a propriedade do objeto associado
        this.ClearValue(ValueProperty);
    }

    internal class SynckingScope : IDisposable
    {
        private readonly CollectionPropertyBehavior parent;

        public SynckingScope(CollectionPropertyBehavior parent)
        {
            this.parent = parent;
            this.parent.syncking = true;
        }

        public void Dispose()
        {
            this.parent.syncking = false;
        }
    }

    internal class ValueProxy : DependencyObject
    {
        public event EventHandler ValueChanged;

        public object Value
        {
            get { return (object)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }
        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value", typeof(object), typeof(ValueProxy), new PropertyMetadata(null, OnValueChanged));


        private static void OnValueChanged(object sender, DependencyPropertyChangedEventArgs args)
        {
            var element = sender as ValueProxy;
            if (element == null || element.ValueChanged == null) return;

            element.ValueChanged(element, EventArgs.Empty);
        }

        public void Bind(object source, string path)
        {
            // Realiza o binding de value com o objeto desejado
            var binding = new Binding(path);
            binding.Source = source;
            binding.Mode = BindingMode.TwoWay;

            BindingOperations.SetBinding(this, ValueProperty, binding);
        }
    }
}
公共类CollectionPropertyBehavior:行为
{
私人可数代理;
私有布尔同步;
公共字符串SourcePropertyPath
{
get{return(string)GetValue(SourcePropertyPathProperty);}
set{SetValue(SourcePropertyPathProperty,value);}
}
公共静态只读DependencyProperty SourcePropertyPathProperty=
Register(“SourcePropertyPath”、typeof(string)、typeof(CollectionPropertyBehavior)、newPropertyMetadata(null));
公共字符串集合属性路径
{
get{return(string)GetValue(CollectionPropertyPathProperty);}
set{SetValue(CollectionPropertyPathProperty,value);}
}
公共静态只读DependencyProperty CollectionPropertyPathProperty=
Register(“CollectionPropertyPath”、typeof(string)、typeof(CollectionPropertyBehavior)、new PropertyMetadata(null));
私有IEnumerable项{get{返回this.ItemsSource==null?null:this.ItemsSource.OfType();}
公共IEnumerable ItemsSource
{
get{return(IEnumerable)GetValue(ItemsSourceProperty);}
set{SetValue(ItemsSourceProperty,value);}
}
公共静态只读依赖项Property ItemsSourceProperty=
DependencyProperty.Register(“ItemsSource”,typeof(IEnumerable),typeof(CollectionPropertyBehavior),new PropertyMetadata(null,ItemsSourceChanged));
私有对象值
{
获取{return(object)GetValue(ValueProperty);}
set{SetValue(ValueProperty,value);}
}
私有静态只读DependencyProperty ValueProperty=
Register(“Value”、typeof(object)、typeof(CollectionPropertyBehavior)、newpropertyMetadata(null、ValueChanged));
公共对象默认值
{
获取{return(object)GetValue(DefaultValueProperty);}
set{SetValue(DefaultValueProperty,value);}
}
公共静态只读从属属性DefaultValueProperty=
附属国