wpf datagrid根据选定的值生成行 [英] wpf datagrid generate rows according to a selected value
问题描述
public enum StabilityLevel
{
Unstable,
Neutral,
Stable
}
public enum WindspeedClass
{
Class1,
Class2,
Class3
}
Windrose:
Windrose:
public class Windrose
{
// percentual value for given direction
private short[][][] _percentage;
// average wind speed in wind speed classes
private float[][] _average;
public Windrose()
{
_percentage = new short[Enum.GetNames(typeof(StabilityLevel)).Length][][];
foreach (StabilityLevel stability in EnumUtil.GetValues<StabilityLevel>())
{
_percentage[(int) stability] = new short[Enum.GetNames(typeof(WindspeedClass)).Length][];
foreach (WindspeedClass windspeed in EnumUtil.GetValues<WindspeedClass>())
{
// We reserve 0 for a special no-wind value, and we limit the maximum number of directions to 36
_percentage[(int) stability][(int) windspeed] = new short[37];
}
}
_average = new float[Enum.GetNames(typeof(StabilityLevel)).Length][];
foreach (StabilityLevel stability in EnumUtil.GetValues<StabilityLevel>())
{
_average[(int) stability] = new float[Enum.GetNames(typeof(WindspeedClass)).Length];
}
NumberOfDirections = 8;
}
public string Name { get; set; }
public int NumberOfDirections { get; set; }
public StabilityLevel StabilityLevel { get; set; }
public WindspeedClass Windspeed { get; set; }
public short[] Percentage
{
get
{
return _percentage[(int) StabilityLevel][(int) Windspeed];
}
}
public float Average
{
get
{
return _average[(int) StabilityLevel][(int) Windspeed];
}
set
{
_average[(int)StabilityLevel][(int)Windspeed] = value;
}
}
}
查看:
现在我们来看看这个视图(xaml),它用作创建一个新的风玫瑰的模态窗口:
View:
Now let's look at this view (xaml) that is used as a modal window for creating a new windrose:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Name" />
<TextBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="1" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Number of directions" />
<ComboBox Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" SelectedItem="{Binding Path=NumberOfDirections, UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem Content="4" />
<ComboBoxItem Content="8" />
<ComboBoxItem Content="12" />
<ComboBoxItem Content="16" />
<ComboBoxItem Content="36" />
</ComboBox>
<Label Grid.Row="2" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Stability Level" />
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Vertical">
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Unstable}}" Content="A - Unstable" />
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Neutral}}" Content="B - Neutral" />
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Stable}}" Content="C - Stable" />
</StackPanel>
<Grid Grid.Row="3" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<RadioButton Grid.Row="0" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class1}}" Content="1 - 0 to 2 meters per second" />
<TextBox Grid.Row="0" Grid.Column="1" Width="30" Text="{Binding Path=???, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
<RadioButton Grid.Row="1" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class2}}" Content="2 - 2 to 4 meters per second" />
<TextBox Grid.Row="1" Grid.Column="1" Width="30" Text="{Binding Path=???, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
<RadioButton Grid.Row="2" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class3}}" Content="3 - over 4 meters per second" />
<TextBox Grid.Row="2" Grid.Column="1" Width="30" Text="{Binding Path=???, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
</Grid>
<DataGrid Grid.Row="4" Margin="5" ItemsSource="{Binding Percentage}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Wind direction" Width="SizeToHeader">
</DataGridTextColumn>
<DataGridTemplateColumn Header="Percentage" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding ???}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
因此,对于每个稳定性级别< - >'风速类'对,windrose实例保持一组37个值和一个额外的浮点值。
So for each 'stability level' <-> 'windspeed class' pair, the windrose instance keeps an array of 37 values and an extra float value.
我不知道如何做2件事:
I don't know how to do 2 things:
我不知道如何创建这个表(DataGrid)。我希望能够根据所选的NumberOfDirections来更改动态生成的行数。
所选的NumberOfDirections也会确定两个后续行之间的step(360度除以NumberOfDirections)。
I don't know how to create this table (DataGrid). I want to be able to change the number of rows that are generated dynamically according to the selected NumberOfDirections. The selected NumberOfDirections also determine the "step"(360 degrees is divided by NumberOfDirections) between two subsequent rows.
在具有x的网格中:Name =WSClass我希望能够将_average数组的项绑定到TextBoxes,以便每个TextBox对应于某个RadioButton(代表风速类)
具有值_average [选择的稳定性] [相应的RadioButton的风速]。
In grid with x:Name="WSClass" I would like to be able to bind items of _average array to the TextBoxes so that each TextBox that corresponds to a certain RadioButton(that represents a wind speed class) has value _average[selected stability][windspeed of the corresponding RadioButton].
推荐答案
编辑(22.11.2013):
相关问题,了解如何实现这一目标的机制。
用户谢里丹已经回答了。因为我不能要求他在这个问题的背景下重写他的解决方案(windroses),所以我决定让这个回答正确的唯一方法是回答我自己的问题。
EDIT (22.11.2013):
I have asked a related question about the bare mechanics of how this could be achieved.
User Sheridan has answered it there. As I cannot ask him to rewrite his solution to my problem in the context of this question (windroses) I decided the only way to have this answered properly is to answer my own question.
警告:长发
public enum StabilityLevel
{
Unstable,
Neutral,
Stable
}
public enum WindspeedClass
{
Class1,
Class2,
Class3
}
public class Windrose
{
#region Fields
// percentual value for given direction
private short[][][] _percentage;
// average wind speed in wind speed class for given stability level
private float[][] _average;
#endregion
public Windrose() { ... initialization ... }
#region Properties
public string Name { get; set; }
public int NumberOfDirections { get; set; }
public StabilityLevel StabilityLevel { get; set; }
public WindspeedClass Windspeed { get; set; }
// indexer
public short this[StabilityLevel stability, WindspeedClass windspeedClass, int direction]
{
get
{
return _percentage[(int) stability][(int) windspeedClass][direction];
}
set
{
_percentage[(int)stability][(int)windspeedClass][direction] = value;
}
}
#endregion
}
查看模型类:
WindroseWindDirection:
As 谢里丹建议我创建了一个数据类型类来保存我需要在datagrid行中显示的所有信息。
View Model classes:
WindroseWindDirection:
As Sheridan suggested I created a data type class to hold all information that I need to display in a datagrid row.
因此
- 它实现
INotifyPropertyChanged
界面 - 为我要在datagrid中显示的每列实现一个属性
public class WindroseWindDirection : INotifyPropertyChanged
{
private string _direction;
private short _directionValue;
#region Construction
public WindroseWindDirection() : this("not available",0) {}
public WindroseWindDirection(string direction, short defaultDirectionValue)
{
_direction = direction;
_directionValue = defaultDirectionValue;
}
#endregion
#region Properties
public string Direction
{
get
{
return _direction;
}
set
{
if (String.Compare(_direction, value) != 0)
{
_direction = value;
OnPropertyChanged("Direction");
}
}
}
public short DirectionValue
{
get
{
return _directionValue;
}
set
{
if (_directionValue != value)
{
OnPropertyChanged("DirectionValue");
_directionValue = value;
}
}
}
#endregion
#region INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
AddModifyWindroseDialogViewModel :
ComboBox $ c $
ObservableCollection< int>
c $和$ code> ObservableCollection< WindroseWindDirection< WindroseWindDirection> StabilityLevel
< - > WindspeedClass
。因为用户必须能够一次编辑所有这些信息,我们为它创建一个锯齿状数组。
AddModifyWindroseDialogViewModel:
There is an ObservableCollection<int>
for the ComboBox
in the view and an ObservableCollection<WindroseWindDirection>
for each combination of StabilityLevel
<-> WindspeedClass
. Because a user has to be able to edit all this information at once we create a jagged array for it.
基本上,这个想法是基于2个属性的值规定稳定性水平和风速等级,我们通过第三个属性返回适当的 ObservableCollection< WindroseWindDirection>
。如果用户更改了整个windrose的路线数量,我们将调用私有方法 UpdateFilteredItems()
。有一个 ObservableCollection< WindroseWindDirection>
实际上允许我们将它绑定到DataGrid的 ItemsSource
,然后定义DataGrid我们自己并且具有绑定到列的 WindroseWindDirection
的各个属性。
Basically the idea is that based on the value of 2 properties that dictate the stability level and windspeed class we return the appropriate ObservableCollection<WindroseWindDirection>
through third property. If the user changes the number of directions for the whole windrose, we'll call a private method UpdateFilteredItems()
. Having an ObservableCollection<WindroseWindDirection>
actually allows us to bind it to the ItemsSource
of the DataGrid and subsequently define the Columns of DataGrid ourselves and have the individual properties of WindroseWindDirection
bound to the columns.
// just for reference: MVVM Light base view model class is used
public class AddModifyWindroseDialogViewModel : ViewModelBase
{
#region Fields
// holds the actual model class
private Windrose _wr;
// holds an ObservableCollection for each combination of StabilityLevel & WindspeedClass
private ObservableCollection<WindroseWindDirection>[][] _dataGrid;
// for Combobox
private ObservableCollection<int> _numberOfDirectionValues = new ObservableCollection<int>(Constants.WindroseAllowedNumberOfDirections);
#endregion
#region Construction
public AddModifyWindroseDialogViewModel(Windrose windrose)
{
_wr = windrose;
// create array[][] of observable collections, one for each stability <-> windspeed pair
_dataGrid = new ObservableCollection<WindroseWindDirection>[Enum.GetNames(typeof(StabilityLevel)).Length][];
int step = 360 / NumberOfDirections;
foreach (StabilityLevel stability ... )
{
_dataGrid[(int) stability] = new ObservableCollection<WindroseWindDirection>[Enum.GetNames(typeof(WindspeedClass)).Length];
foreach (WindspeedClass windspeed ... )
{
_dataGrid[(int)stability][(int)windspeed] = new ObservableCollection<WindroseWindDirection>();
// Add 'No wind' special first row
_dataGrid[(int)stability][(int)windspeed].Add(new WindroseWindDirection("No wind", _wr[stability, windspeed, 0]));
// Add the rest
for (int i = 0; i < NumberOfDirections; i++)
{
_dataGrid[(int)stability][(int)windspeed].Add(new WindroseWindDirection(String.Format("{0} degrees", i * step), _wr[stability, windspeed, i + 1]));
}
}
}
}
#endregion
#region Properties
public String Name
{
get
{
return _wr.Name;
}
set
{
if (String.Equals(_wr.Name, value) == false)
{
_wr.Name = value;
RaisePropertyChanged("Name");
}
}
}
public int NumberOfDirections
{
get
{
return _wr.NumberOfDirections;
}
set
{
if (_wr.NumberOfDirections != value)
{
_wr.NumberOfDirections = value;
RaisePropertyChanged("NumberOfDirections");
UpdateFilteredItems();
}
}
}
public ObservableCollection<int> NumberOfDirectionsValues
{
get
{
return _numberOfDirectionValues;
}
}
public StabilityLevel StabilityLevel
{
get
{
return _wr.StabilityLevel;
}
set
{
if (Enum.Equals(_wr.StabilityLevel, value) == false)
{
_wr.StabilityLevel = value;
RaisePropertyChanged("StabilityLevel");
RaisePropertyChanged("FilteredItems");
RaisePropertyChanged("WindSpeedAverageClass1");
RaisePropertyChanged("WindSpeedAverageClass2");
RaisePropertyChanged("WindSpeedAverageClass3");
}
}
}
public WindspeedClass Windspeed
{
get
{
return _wr.Windspeed;
}
set
{
if (Enum.Equals(_wr.Windspeed, value) == false)
{
_wr.Windspeed = value;
RaisePropertyChanged("Windspeed");
RaisePropertyChanged("FilteredItems");
}
}
}
public ObservableCollection<WindroseWindDirection> FilteredItems
{
get
{
return _dataGrid[(int) StabilityLevel][(int) Windspeed];
}
}
public float WindSpeedAverageClass1
{
get
{
return _wr[StabilityLevel, WindspeedClass.Class1];
}
set
{
if (_wr[StabilityLevel, WindspeedClass.Class1] != value)
{
_wr[StabilityLevel, WindspeedClass.Class1] = value;
RaisePropertyChanged("WindSpeedAverageClass1");
}
}
}
public float WindSpeedAverageClass2
{
get
{
return _wr[StabilityLevel, WindspeedClass.Class2];
}
set
{
if (_wr[StabilityLevel, WindspeedClass.Class2] != value)
{
_wr[StabilityLevel, WindspeedClass.Class2] = value;
RaisePropertyChanged("WindSpeedAverageClass2");
}
}
}
public float WindSpeedAverageClass3
{
get
{
return _wr[StabilityLevel, WindspeedClass.Class3];
}
set
{
if (_wr[StabilityLevel, WindspeedClass.Class3] != value)
{
_wr[StabilityLevel, WindspeedClass.Class3] = value;
RaisePropertyChanged("WindSpeedAverageClass3");
}
}
}
#endregion
private void UpdateFilteredItems()
{
/**/
int step = 360 / NumberOfDirections;
foreach (StabilityLevel stability ... )
{
foreach (WindspeedClass windspeed ... )
{
// Clear the old values
_dataGrid[(int)stability][(int)windspeed].Clear();
// Add 'No wind' special value
_dataGrid[(int)stability][(int)windspeed].Add(new WindroseWindDirection("No wind", _wr[stability, windspeed, 0]));
// Add degrees
for (int i = 0; i < NumberOfDirections; i++)
{
_dataGrid[(int)stability][(int)windspeed].Add(new WindroseWindDirection(String.Format("{0} degrees", i * step), _wr[stability, windspeed, i + 1]));
}
}
}
RaisePropertyChanged("FilteredItems");
}
}
查看:
View :
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Name" />
<TextBox Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Text="{Binding Path=Name, UpdateSourceTrigger=PropertyChanged}" />
<Label Grid.Row="1" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Number of directions" />
<ComboBox Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" SelectedItem="{Binding Path=NumberOfDirections, UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem Content="4" />
<ComboBoxItem Content="8" />
<ComboBoxItem Content="12" />
<ComboBoxItem Content="16" />
<ComboBoxItem Content="36" />
</ComboBox>
<Label Grid.Row="2" HorizontalAlignment="Left" ContentStringFormat="{}{0}:" Content="Stability Level" />
<StackPanel Grid.Row="2" Grid.Column="1" Orientation="Vertical">
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Unstable}}" Content="A - Unstable" />
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Neutral}}" Content="B - Neutral" />
<RadioButton HorizontalAlignment="Left" IsChecked="{Binding Path=StabilityLevel, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:StabilityLevel.Stable}}" Content="C - Stable" />
</StackPanel>
<Grid Grid.Row="3" Grid.ColumnSpan="2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox Grid.Row="1" Grid.Column="1" Width="30" Text="{Binding Path=WindSpeedAverageClass2, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
<RadioButton Grid.Row="0" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class1}}" Content="1 - 0 to 2 meters per second" />
<TextBox Grid.Row="0" Grid.Column="1" Width="30" Text="{Binding Path=WindSpeedAverageClass1, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
<RadioButton Grid.Row="1" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class2}}" Content="2 - 2 to 4 meters per second" />
<TextBox Grid.Row="1" Grid.Column="1" Width="30" Text="{Binding Path=WindSpeedAverageClass2, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
<RadioButton Grid.Row="2" HorizontalAlignment="Left" IsChecked="{Binding Path=Windspeed, Converter={StaticResource EnumToBoolConverter}, ConverterParameter={x:Static model:WindspeedClass.Class3}}" Content="3 - over 4 meters per second" />
<TextBox Grid.Row="2" Grid.Column="1" Width="30" Text="{Binding Path=WindSpeedAverageClass3, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
</Grid>
<!-- Here is the DataGrid. Please notice how ObservableCollection<WindroseWindDirection> is bound to the DataGrid ItemsSource and how individual columns are bound with properties of WindroseWindDirection -->
<DataGrid Grid.Row="4" Margin="5" ItemsSource="{Binding FilteredItems}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Wind Direction" Width="SizeToHeader" Binding="{Binding Direction}">
</DataGridTextColumn>
<DataGridTemplateColumn Header="Percent" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding DirectionValue, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
这篇关于wpf datagrid根据选定的值生成行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!