【问题标题】:wpf datagrid generate rows according to a selected valuewpf datagrid 根据选定的值生成行
【发布时间】:2013-11-29 18:49:10
【问题描述】:

型号:

枚举:

public enum StabilityLevel
{
    Unstable,
    Neutral,
    Stable
}

public enum WindspeedClass
{
    Class1,
    Class2,
    Class3
}

风玫瑰:

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),它被用作创建新 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 个值和一个额外浮点值的数组。

我不知道怎么做 2 件事:

A)

我不知道如何创建这个表(DataGrid)。我希望能够根据所选的 NumberOfDirections 更改动态生成的行数。 选定的 NumberOfDirections 还决定了两个后续行之间的“步长”(360 度除以 NumberOfDirections)。

B)

在 x:Name="WSClass" 的网格中,我希望能够将 _average 数组的项目绑定到 TextBoxes,以便每个 TextBox 对应于某个 RadioButton(代表风速类) 具有值 _average[选定的稳定性][相应 RadioButton 的风速]。

【问题讨论】:

    标签: c# wpf mvvm binding datagrid


    【解决方案1】:

    编辑(2013 年 11 月 22 日):
    我已经向related question 询问了如何实现这一点的基本机制。 用户Sheridan 已在那里回答。由于我不能要求他在这个问题(windroses)的背景下重写他对我的问题的解决方案,我决定正确回答这个问题的唯一方法是回答我自己的问题。

    警告:长帖

    模型类:

    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    
    
    }
    

    查看模型类:

    风玫瑰风向:

    作为Sheridan suggested,我创建了一个数据类型类来保存我需要在数据网格行中显示的所有信息。

    因此

    • 它实现了INotifyPropertyChanged接口
    • 为要在数据网格中显示的每一列实现一个属性


    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 有一个ObservableCollection&lt;int&gt;StabilityLevel 的每个组合都有一个ObservableCollection&lt;WindroseWindDirection&gt; WindspeedClass。因为用户必须能够一次编辑所有这些信息,所以我们为其创建了一个锯齿状数组。

    基本上,这个想法是基于 2 个属性的值,这些属性决定稳定性级别和风速等级,我们通过第三个属性返回适当的 ObservableCollection&lt;WindroseWindDirection&gt;。如果用户更改整个风玫瑰的方向数,我们将调用私有方法UpdateFilteredItems()。拥有ObservableCollection&lt;WindroseWindDirection&gt; 实际上允许我们将它绑定到DataGrid 的ItemsSource,然后我们自己定义DataGrid 的列,并将WindroseWindDirection 的各个属性绑定到列。

    // 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");
            }                                            
    
    }
    

    查看:

    <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>   
    

    【讨论】:

      猜你喜欢
      • 2013-09-05
      • 1970-01-01
      • 2016-10-13
      • 1970-01-01
      • 2011-04-24
      • 2011-05-31
      • 2013-03-10
      • 2010-12-30
      • 2016-08-11
      相关资源
      最近更新 更多