tags:

views:

175

answers:

2

Currently my model has ten properties which for our purposes here I'll call AnnualizedRate1, AnnualizedRate2, ..., AnnualizedRate10 which are revealed to views in the view model via ten properties Rate1, Rate2, ..., Rate10. One of my views shows these values in a DataGrid. This is awfully repetitious and a pain to adapt to changing requirements. There has to be a better way than the following.

Model (MyModel):

public decimal AnnualizedRate1 { get { return this.AnnualizedRate(1); } }
public decimal AnnualizedRate2 { get { return this.AnnualizedRate(2); } }
...
public decimal AnnualizedRate10 { get { return this.AnnualizedRate(10); } }

where MyModel.AnnualizedRate is

public decimal AnnualizedRate(int i);

View Model (MyViewModel):

public decimal Rate1 { get { return myModel.AnnualizedRate1; } }
public decimal Rate2 { get { return myModel.AnnualizedRate2; } }
...
public decimal Rate10 { get { return myModel.AnnualizedRate10; } }

View (MyView):

xmlns:dg="http://schemas.microsoft.com/wpf/2008/toolkit"
...
    <dg:DataGrid>
        <dg:DataGrid.Columns>
            <dg:DataGridTextColumn
                Header="Rate1" 
                Binding="{Binding Rate1, StringFormat=P}"
                IsReadOnly="True"/>
            <dg:DataGridTextColumn
                Header="Rate2" 
                Binding="{Binding Rate2, StringFormat=P}"
                IsReadOnly="True"/>
            ...
            <dg:DataGridTextColumn
                Header="Rate10" 
                Binding="{Binding Rate10, StringFormat=P}"
                IsReadOnly="True"/>
        </dg:DataGrid.Columns>
    </dg:DataGrid>

Does anyone have any ideas?

A: 

I would use and ObservableCollection to store the data and bind the grid to.

RB Davidson
Please elaborate. I am not seeing how to use this.
Jason
I don't see why he got downvoted. This is the correct answer. I will write the code for you, but it was kinda crap to downvote him.
Anderson Imes
@Anderson Imes: The downvote is not from me.
Jason
Gotcha. Hard to tell on here.
Anderson Imes
+3  A: 

Here is the code to do what RB Davidson said to do. When you find that this does what you wanted, please give him credit. His answer is correct.

In your ViewModel:

public class AnnualizedRateViewModel
{
     public string Name { get; set; }
     public decimal Rate { get; set; }
}

public MyViewModel : INotifyPropertyChanged
{

public MyViewModel()
{
     AnnualizedRates = new ObservableCollection<AnnualizedRateViewModel>();
     //I'd recommend your model having a GetAllRates() function rather than this,
     //but for demo purposes, this works
     for(int i = 1; i <= 10; i++)
     {
          AnnualizedRates.Add(new AnnualizedRateViewModel()
          {
               Name = string.Format("Rate {0}", i),
               Rate = MyModel.AnnualizedRate(i)
          });
     }
}

private ObservableCollection<int> _annualizedRates;
public ObservableCollection<int> AnnualizedRates
{
     get { return _annualizedRates; }
     set
     {
          _annualizedRates = value;
          //Raise OnNotifyPropertyChanged event from your
          //implementation of INotifyPropertyChanged in your viewmodel
          //the full implementation of this is outside the scope of this demo
     }
}

}

From there you'd actually use databinding to create the columns in your view. You'd bind to this collection of AnnualizedRates. Since the WPF Toolkit doesn't make this easy, you'll have to write a value converter to convert the ObservableCollection<AnnualizedRateViewModel> to an ObservableCollection<DataGridColumn>.

<dg:DataGrid AutoGenerateColumns="false" Columns="{Binding AnnualizedRates, ValueConverter={StaticResource AnnualizedRatesToDataGridColumnCollectionConverter}}">
</dg:DataGrid>

The thing you should learn here is when you are thinking to yourself "repetition", try and instead think "collection".

Good luck... and again, credit RB Davidson.

Anderson Imes
I'm not sure davidson meant bind columns instead of items - at least his answer does not mention this.
Sergey Aldoukhov
I saw it as implied. The strategy is sound and he didn't deserve all of the downvotes. Asking for clarification is fine, but he was also downvoted which I think is a little harsh.
Anderson Imes
I could very well be mistaken, but I do not think that the WPF Toolkit DataGrid.Columns property has an ItemsControl property. I believe that you are confusing a GridView with the DataGrid. Please forgive me if I am wrong.
Jason
An ItemsControl is a control that is sort of like a generic repeater. Since you can compose anything in WPF, I'm inserting an ItemsControl into your Columns collection that should generate columns on its own. More about the ItemsControl here: http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.aspx. Like I said... this is likely not 100% correct but it's at least 95% of the way there.
Anderson Imes
Also you are reading that wrong. When I say <DataGrid.Columns.. I'm referring to the Columns property of the DataGrid, however what you are doing there is setting the Columns property equal to everything contained within that tag. The equivalent (if you could do this) would be <DataGrid Columns="<ItemsControl...">. You can't do that though, so that's why XAML has this property syntax for assigning complex types to a property.
Anderson Imes
@Anderson Imes: DataGrid.Columns is merely an ObservableCollection. It does not inherit from ItemsControl.
Jason
A good example to teach yourself this is to understand <TextBlock Text="Blah"/> and <TextBlock><TextBlock.Text>Blah</TextBlock.Text></TextBlock> are identical statements. Both assign "Blah" to the property "Text".
Anderson Imes
Ugh... the WPF Toolkit is so crazy sometimes. I'll update the sample.
Anderson Imes
Updated with a ValueConverter that converts from ObservableCollection<AnnualizedRateViewModel> to ObservableCollection<DataGridColumn>. This is why I don't use the DataGrid... too inflexible without writing code... doesn't keep compositing in mind.
Anderson Imes
@Anderson Imes: I'll give this suggestion a try. Thanks for your suggestions so far tonight.
Jason
Also I didn't provide the code for the converter. It should be pretty self explanatory. http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx
Anderson Imes
@Anderson Imes: "Also you are reading that wrong. When I say <DataGrid.Columns.. I'm referring to the Columns property of the DataGrid, however what you are doing there is setting the Columns property equal to everything contained within that tag." I understand all that. What I am trying to say is that you can't assign an ItemsControl to Columns. Sorry for not being clear.
Jason
@Anderson Imes: "Also I didn't provide the code for the converter." No problem. I think I can handle that. Really appreciate all the effort.
Jason
@Anderson Imes: Thank you for your support of my answer. And yes, I did mean to imply binding to columns instead of items. To be honest, even though I knew the approach I was suggesting was right, I would have had a hard time producing the code you did. I am, at best, mediocre with WPF. Therefore, even though I had the initial right idea I think you deserve credit for supplying the more useful and accurate answer.
RB Davidson