2014-09-08 5 views
1

Вот проблема с использованием WPF и Datagrid.Показать много столбцов в WPF DataGrid

Есть много объектов, которые пользователи хотят видеть в виде строк в таблице, где столбцы - это даты.

| Name  |Jan 2014|Feb 2014|Mar 2014|...| 
-------------------------------------------- 
| coolObj1 | 10.0| 10.0| 20.0|...| 
| coolObj2 | 15.0| 19.0| 25.0|...| 

Мои вопросы:

  • Этот код работает, но не имеют представления о том, как правильно осуществить проверку. Что делать, если значения не будут только удваиваться (это тоже могут быть int или строки)?
  • Что делать, если пользователи хотят ограничить некоторые значения диапазона [0..50]?
  • Есть ли способ создать эти столбцы с помощью XAML?
  • Возможно, существуют более подходящие способы представления таких данных «много столбцов»?

В Qt было много способов работы с ситуациями, как это (используйте QAbstractItemModel дурачок!)

Screenshot of result

XAML Код:

<Window x:Class="Columns.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Find easter eggs" Height="350" Width="525"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="Auto" /> 
      <RowDefinition Height="*" /> 
     </Grid.RowDefinitions> 
     <Button Grid.Row="0" HorizontalAlignment="Left" Margin="5" Click="OnClick">Update grid</Button> 
     <DataGrid x:Name="Grid" 
        CanUserAddRows="False" 
        CanUserDeleteRows="False" 
        CanUserResizeRows="False" 
        CanUserReorderColumns="False" 
        CanUserResizeColumns="True" 
        CanUserSortColumns="False" 
        Grid.Row="1" /> 
    </Grid> 
</Window> 

Xaml.cs код:

namespace Columns 
{ 
    public partial class MainWindow 
    { 
     private SomeDict _dict; 

     public MainWindow() 
     { 
      InitializeComponent(); 
      GetData(); 
      UpdateView(); 
     } 

     private void GetData() 
     { 
      // We assume that there can be a lot of dicts 
      // Currently we work with the only one 

      _dict = new SomeDict(); 
      Random rnd = new Random(); 

      var start = new DateTime(2010, 1, 1); 
      var end = new DateTime(2020, 1, 1); 

      for (DateTime date = start; date < end; date = date.AddMonths(1)) 
      { 
       _dict.Add(date, rnd.NextDouble()); 
      } 
     } 

     private void UpdateView() 
     { 
      var row = new RowContext(); 

      // Create name column 
      string columnName = "Name"; 
      ICellContext cellContext = new NameCell("Easter egg"); 
      row[columnName] = cellContext; 

      Grid.Columns.Clear(); 
      Grid.Columns.Add(new DataGridTextColumn() 
      { 
       Binding = new Binding(columnName), 
       Header = columnName, 
       Width = 100, 
      }); 

      var stringToDoubleConverter = new StringToDoubleConverter(); 

      // Create column for each date in dictionary 

      foreach (var pair in _dict) 
      { 
       DateTime date = pair.Key; 
       columnName = AsColumnName(date); 

       Grid.Columns.Add(new DataGridTextColumn() 
       { 
        Binding = new Binding(columnName) 
        { 
         StringFormat = "N3", 
         Mode = BindingMode.TwoWay, 
         Converter = stringToDoubleConverter, 
        }, 
        IsReadOnly = false, 
        Width = 80, 
        Header = AsReadable(date), 
       }); 

       cellContext = new CellContext(_dict, date, typeof (double), pair.Value); 
       row[columnName] = cellContext; 
      } 

      // Finally set ItemsSource 
      Grid.ItemsSource = new[] {row}; 
     } 

     private string AsReadable(DateTime date) 
     { 
      return date.ToString("d"); 
     } 

     private string AsColumnName(DateTime date) 
     { 
      return date.ToString("yy-MM-dd"); 
     } 

     private void OnClick(object sender, RoutedEventArgs e) 
     { 
      UpdateView(); 
     } 
    } 

    public interface ICellContext 
    { 
     object Value { get; set; } 
     bool IsEditable { get; } 
     Type PropertyType { get; } 
    } 

    internal sealed class NameCell : ICellContext 
    { 
     private string _name; 

     public NameCell(string name) 
     { 
      _name = name; 
     } 

     public object Value 
     { 
      get { return _name; } 
      set { } 
     } 

     public bool IsEditable 
     { 
      get { return false; } 
     } 

     public Type PropertyType 
     { 
      get { return typeof(string); } 
     } 
    } 

    internal sealed class CellContext : ICellContext, INotifyPropertyChanged 
    { 
     private readonly bool _isEditable; 
     private readonly SomeDict _dict; 
     private readonly DateTime _date; 
     private readonly Type _propertyType; 
     private object _initialValue; 

     /// <summary> 
     ///  Initializes a new instance of the <see cref="T:System.Object" /> class. 
     /// </summary> 
     public CellContext(SomeDict dict, DateTime date, Type propertyType, object initialValue, bool isEditable=true) 
     { 
      _dict = dict; 
      _date = date; 
      _propertyType = propertyType; 
      _initialValue = initialValue; 
      _isEditable = isEditable; 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 

     public object Value 
     { 
      get { return _initialValue; } 
      set 
      { 
       Debug.Assert(value.GetType() == PropertyType); 
       if (Equals(value, _initialValue)) return; 

       // Create do/undo action, write value 
       _dict[_date] = Convert.ToDouble(value); 
       _initialValue = value; 

       OnPropertyChanged("Value"); 
      } 
     } 

     public bool IsEditable 
     { 
      get { return _isEditable; } 
     } 

     public Type PropertyType 
     { 
      get { return _propertyType; } 
     } 

     [NotifyPropertyChangedInvocator] 
     private void OnPropertyChanged(string propertyName) 
     { 
      var handler = PropertyChanged; 
      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public sealed class RowContext : DynamicObject, INotifyPropertyChanged 
    { 
     private readonly IDictionary<string, object> data; 

     public RowContext() 
     { 
      data = new Dictionary<string, object>(); 
     } 

     public object this[string columnName] 
     { 
      get 
      { 
       object value; 
       if (data.TryGetValue(columnName, out value)) 
       { 
        var iproperty = value as ICellContext; 
        if (iproperty != null) 
        { 
         return iproperty.Value; 
        } 

        return value; 
       } 

       return null; 
      } 
      set 
      { 
       object value1; 
       if (!data.TryGetValue(columnName, out value1)) 
       { 
        data.Add(columnName, value); 
        OnPropertyChanged(columnName); 
       } 
       else 
       { 
        var iproperty = value1 as ICellContext; 
        if (iproperty != null) 
        { 
         iproperty.Value = value; 
         OnPropertyChanged(columnName); 
        } 
        else if (value1 != value) 
        { 
         data[columnName] = value; 
         OnPropertyChanged(columnName); 
        } 
       } 
      } 
     } 

     public override IEnumerable<string> GetDynamicMemberNames() 
     { 
      return data.Keys; 
     } 

     public override bool TryGetMember(GetMemberBinder binder, out object result) 
     { 
      result = this[binder.Name]; 
      return true; 
     } 

     public override bool TrySetMember(SetMemberBinder binder, object value) 
     { 
      this[binder.Name] = value; 
      return true; 
     } 

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

     #region INotifyPropertyChanged Members 

     public event PropertyChangedEventHandler PropertyChanged; 

     #endregion 
    } 

    internal sealed class SomeDict : Dictionary<DateTime, object> 
    { 
    } 
} 
+1

Да, вы можете сделать это в XAML, если все заранее определено. Однако валидация - это все другое животное. Не могли бы вы вообще сузить вопрос? – BradleyDotNET

+0

@ Rustam объясните мне, что вам нужно http://chat.stackoverflow.com/rooms/18165/wpf –

+0

@BradleyDotNET, я знаю, что если все столбцы известны (например, свойства какого-либо объекта), будет способ чтобы определить это в XAML. Но что, если диапазон дат изменчив? –

ответ

1

Это что существует только два способа реализации такого поведения:

  1. Использование DynamicObject, как в примере выше.
  2. С помощью DataTable
Смежные вопросы