我在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>
答案 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 中的
和datagrid 我知道这是非常努力的,但这是我在现实世界中的方式。 更新2: 因此,经过更正后,我们可以看一下示例代码。 <强> Entry.cs 强> <强> Viewmodel.cs 强> <强> MainWindow.xaml 强> 现在,在更改第一行的日期时,您会看到数据网格下方所选天数的计数。请注意,所选日期的默认绑定模式是OneWay。您必须指定 尝试一下,给我一些反馈。<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="" 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 ItemsSource="{Binding Collection}">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:DropDownDayPicker SelectedWeekdays="{Binding whatEver}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
我试着为你制作一个样品,并注意到我犯了一个小错误。请参阅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;
}
}
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;
}
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; }
}
}
<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>
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