带有复选框

时间:2015-11-28 16:14:54

标签: c# wpf datagrid

我在WPF中有一个数据网格绑定到我在XML文件中读取/保存的ObservableCollection。我现在想添加一个带复选框或类似内容的组合框。 应该有一个下拉菜单,用于选择一个或多个工作日。

有没有人可以帮助我?

提前致谢!

修改

在实现christoph的自定义控件(DropDownDayPicker)之后,我可以将数据绑定到它,但不是以其他方式绑定(如果更改则获取更新的值) 所以这就是我的尝试:

我的对象: Entry.cs

public class Entry : INotifyPropertyChanged
{
    string Id;
    string ExecuteOn;
}

MyWindow.xaml.cs:

public ObservableCollection<Entry> entryList;

        doc.Load("C:\\test\\list.xml");
        XmlElement root = doc.DocumentElement;
        XmlNodeList nodes = root.SelectNodes("Entry");
        foreach(XmlNode node in nodes)
        {
            XmlNodeList subnodes = node.SelectNodes("ExecuteOn");
            ObservableCollection<Weekday> days = new ObservableCollection<Weekday>();
            foreach(XmlNode subnode in node["ExecuteOn"].ChildNodes)
                days.Add( (Weekday)Enum.Parse(typeof(Weekday),subnode.InnerText));

            _entryList.Add(new Entry(
                node["Id"].InnerText, 
                node["Description"].InnerText, 
                node["Path"].InnerText, 
                Convert.ToInt32(node["KindOfTask"].InnerText), 
                days
                ));
        }

MyWindow.xaml

<DataGrid x:Name="EntryView" ItemsControl.ItemsSource="{Binding EntryList}" DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}" 
                  AutoGenerateColumns="false" Margin="0,34,0,37" CanUserAddRows="false" Height="Auto">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Days" x:Name="cellExecuteOn" Width="*" >
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <local:DropDownDayPicker SelectedWeekdays="{Binding ExecuteOn}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

这是xml的样子:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEntry>
  <Entry>
    <Id>efbae4da-f833-4d07-a8af-9ec3421b4886</Id>
    <ExecuteOn>
      <Weekday>Montag</Weekday>
      <Weekday>Dienstag</Weekday>
    </ExecuteOn>
  </Entry>
  <Entry>
    <Id>1cb13340-40dd-48c1-ada5-bbb6f79c0d06</Id>
    <ExecuteOn>
      <Weekday>Montag</Weekday>
    </ExecuteOn>
  </Entry>
</ArrayOfEntry>

2 个答案:

答案 0 :(得分:2)

您可以使用DataGridTemplateColumn。尝试这样的事情:

    <DataGrid ItemsSource="{Binding Collection}">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <CheckBox Content="Monday"/>
                            <CheckBox Content="Friday"/>
                        </StackPanel>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

希望符合您的需求。

<强>更新
好的,现在是专业的方法。我为你想要的东西做了一个自定义控件。 (请不要评价一下,你可以自定义它)。这是代码......

Weekday.cs

public enum Weekday
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday
}

DropDownDayPicker.cs

public class DropDownDayPicker : Control
{
    private List<CheckBox> checkboxes = new List<CheckBox>();

    static DropDownDayPicker()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(DropDownDayPicker), new FrameworkPropertyMetadata(typeof(DropDownDayPicker)));
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        StackPanel weekdayBoxes = this.GetTemplateChild("PART_weekdayHost") as StackPanel;

        foreach(CheckBox box in weekdayBoxes.Children)
        {
            box.Checked += Box_CheckedChanged;
            box.Unchecked += Box_CheckedChanged;
            this.checkboxes.Add(box);
        }

        Button openPopup = this.GetTemplateChild("PART_openPopupButton") as Button;
        openPopup.Click += OpenPopup_Click;

        this.UpdateCheckboxes();
    }

    private void OpenPopup_Click(object sender, RoutedEventArgs e)
    {
        Popup popup = this.GetTemplateChild("PART_popup") as Popup;
        popup.IsOpen = !popup.IsOpen;

    }

    private void Box_CheckedChanged(object sender, RoutedEventArgs e)
    {
        this.UpdateSelectedWeekdays();
    }

    public ObservableCollection<Weekday> SelectedWeekdays
    {
        get { return (ObservableCollection<Weekday>)GetValue(SelectedWeekdaysProperty); }
        set { SetValue(SelectedWeekdaysProperty, value); }
    }

    public static readonly DependencyProperty SelectedWeekdaysProperty =
        DependencyProperty.Register("SelectedWeekdays", typeof(ObservableCollection<Weekday>), typeof(DropDownDayPicker), new PropertyMetadata(new ObservableCollection<Weekday>(), SelectedWeekdaysPropertyChanged));

    private static void SelectedWeekdaysPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        DropDownDayPicker picker = sender as DropDownDayPicker;
        ObservableCollection<Weekday> oldValue = args.OldValue as ObservableCollection<Weekday>;
        ObservableCollection<Weekday> newValue = args.NewValue as ObservableCollection<Weekday>;

        if (picker != null)
        {
            if (oldValue != null)
            {
                oldValue.CollectionChanged -= picker.SelectedWeekdaysChanged;
            }

            if (newValue != null)
            {
                newValue.CollectionChanged += picker.SelectedWeekdaysChanged;
            }

            picker.UpdateCheckboxes();
        }
    }

    private void SelectedWeekdaysChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        this.UpdateCheckboxes();
    }

    private bool updating = false;

    private void UpdateCheckboxes()
    {
        if (!this.updating)
        {
            this.updating = true;
            if (this.SelectedWeekdays != null)
            {
                foreach (CheckBox box in this.checkboxes)
                {
                    box.IsChecked = this.SelectedWeekdays.Contains((Weekday)box.Tag);
                }
            }
            this.UpdateSummary();
            this.updating = false;
        }
    }

    private void UpdateSelectedWeekdays()
    {
        if (!this.updating)
        {
            this.updating = true;
            var selectedWeekdays = this.checkboxes.Where(x => x.IsChecked.HasValue && x.IsChecked.Value).Select(x => x.Tag).Cast<Weekday>();
            this.SelectedWeekdays = new ObservableCollection<Weekday>(selectedWeekdays);
            this.UpdateSummary();
            this.updating = false;
        }
    }

    private void UpdateSummary()
    {
        TextBlock summary = this.GetTemplateChild("PART_summary") as TextBlock;
        if (this.SelectedWeekdays != null)
        {                
            if (this.SelectedWeekdays.Count == 0)
            {
                summary.Text = "none";
            }
            else if (this.SelectedWeekdays.Count == 1)
            {
                summary.Text = this.SelectedWeekdays[0].ToString();
            }
            else if (this.SelectedWeekdays.Count > 1)
            {
                summary.Text = string.Format("{0} days",this.SelectedWeekdays.Count);
            }
        }
        else
        {
            summary.Text = "none";
        }
    }
}
Generic.xaml

中的

<Style TargetType="{x:Type local:DropDownDayPicker}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate>
                <Grid>
                    <Button x:Name="PART_openPopupButton">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBlock VerticalAlignment="Center" Margin="3" x:Name="PART_summary"/>
                            <TextBlock FontFamily="Segoe UI Symbol" Text="&#xE0E5;" Grid.Column="1" FontWeight="Bold"/>
                        </Grid>
                    </Button>
                    <Popup PlacementTarget="{Binding ElementName=PART_openPopupButton}" IsOpen="False" x:Name="PART_popup" StaysOpen="False">
                    <StackPanel x:Name="PART_weekdayHost" Background="White">
                        <CheckBox Content="Monday">
                            <CheckBox.Tag>
                                <local:Weekday>Monday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Thusday">
                            <CheckBox.Tag>
                                <local:Weekday>Tuesday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Wednesday">
                            <CheckBox.Tag>
                                <local:Weekday>Wednesday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Thursday">
                            <CheckBox.Tag>
                                    <local:Weekday>Thursday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Friday">
                            <CheckBox.Tag>
                                <local:Weekday>Friday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Saturday">
                            <CheckBox.Tag>
                                <local:Weekday>Saturday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                        <CheckBox Content="Sunday">
                            <CheckBox.Tag>
                                <local:Weekday>Sunday</local:Weekday>
                            </CheckBox.Tag>
                        </CheckBox>
                    </StackPanel>
                    </Popup>
                </Grid>                    
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Width" Value="150"/>
</Style>

和datagrid

<DataGrid ItemsSource="{Binding Collection}">
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:DropDownDayPicker SelectedWeekdays="{Binding whatEver}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

我知道这是非常努力的,但这是我在现实世界中的方式。

更新2:
我试着为你制作一个样品,并注意到我犯了一个小错误。请参阅DropDownDayPicker.cs并更新方法UpdateSelectedWeekdays,如下所示:

    private void UpdateSelectedWeekdays()
    {
        if (!this.updating)
        {
            this.updating = true;
            var selectedWeekdays = this.checkboxes.Where(x => x.IsChecked.HasValue && x.IsChecked.Value).Select(x => x.Tag).Cast<Weekday>();

            SetCurrentValue(DropDownDayPicker.SelectedWeekdaysProperty, new ObservableCollection<Weekday>(selectedWeekdays));
            BindingExpression binding = this.GetBindingExpression(DropDownDayPicker.SelectedWeekdaysProperty);
            if (binding != null)
            {
                binding.UpdateSource();
            }

            this.UpdateSummary();
            this.updating = false;
        }
    }

因此,经过更正后,我们可以看一下示例代码。

<强> Entry.cs

public class Entry : INotifyPropertyChanged
{
    private string title;
    public string Title
    {
        get { return title; }
        set { title = value; this.OnPropertyChanged("Title"); }
    }

    private ObservableCollection<Weekday> days = new ObservableCollection<Weekday>();
    public ObservableCollection<Weekday> Days
    {
        get { return days; }
        set { days = value; this.OnPropertyChanged("Days"); }
    }


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

    public event PropertyChangedEventHandler PropertyChanged;
}

<强> Viewmodel.cs

public class Viewmodel
{
    private ObservableCollection<Entry> collection = new ObservableCollection<Entry>()
    {
        new Entry() { Title = "Entry 1" },
        new Entry() { Title = "Entry 2" },
        new Entry() { Title = "Entry 3" }
    };
    public ObservableCollection<Entry> Collection
    {
        get { return collection; }
        set { collection = value; }
    }
}

<强> MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <local:Viewmodel/>
</Window.DataContext>
<StackPanel>
    <Button Content="Click" Click="Button_Click_1"/>
    <DataGrid ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Title}" Header="Title"/>
            <DataGridTemplateColumn Header="Days">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <local:DropDownDayPicker SelectedWeekdays="{Binding Days, Mode=TwoWay}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>
    <TextBlock Text="{Binding Collection[0].Days.Count}"/>
</StackPanel>
</Window>

现在,在更改第一行的日期时,您会看到数据网格下方所选天数的计数。请注意,所选日期的默认绑定模式是OneWay。您必须指定Mode=TwoWay才能使其正常运行。

尝试一下,给我一些反馈。

答案 1 :(得分:0)

类似于christoph你可以用类似的东西实现一个组合框

  <DataGrid ItemsSource="{Binding SomeCollection}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Id">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Id}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Week Days">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <ComboBox ItemsSource="{Binding Days}"/>   
                            <CheckBox/>
                        </StackPanel>                            
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

其中Days是该类的ObservableCollection中的枚举属性

 public class SomeData
{
    public int Id { get; set; }
    public Days Days { get; set; }

}

 public enum Days
{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
}

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;          
    }

    public ObservableCollection<SomeData> SomeCollection { get; set; }

}

这是了解wpf数据网格的好资源 Datagrid tutorial