0

I am learning WPF and a newbie. I have this requirement. In the view model I have a timespan object. I would like to display the timespan as "one filled circle for each hour". What will be an optimal way to do this in WPF way. I tried the ItemsTemplate but couldnot find a way to do this.

4

3 回答 3

2

Have a look at this article about creating a Rating Control It would be very similar.

The only MVVM thing about this might be how you gather the actual value that should be shown in the control. But building a control hasn't much to do with MVVM.

Let us know if you get stuck and try to ask specific questions.

于 2013-09-26T06:47:06.247 回答
0

One option is to create custom control that will generate to correct number of circles in code but if you prefer to mainly use XAML you have a few options.

If you want the circles to be generated inside a panel you can use an ItemsControl to perform the generation. The items generated are the circles so you need a view-model property with an element for each whole hour. These elements does not have any properties and can simply be of type Object:

public ObservableCollection<Object> Items { get; private set; }

You can update the number of objects in the collection:

Items.Clear();
var item = new Object();
for (var i = 0; i < timeSpan.Hours; i += 1)
    Items.Add(item);

A simple view is then:

<ItemsControl ItemsSource="{Binding Items}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <Ellipse Width="25" Height="25" Fill="Black" StrokeThickness="0" Margin="10"/>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

If you want to layout the circles in a manner that is hard to do using a panel you can instead manually layout 24 circles in the XAML. You can then use a value converter to hide or show each circle based on a view-model property representing the hours:

// Remember to fire INotifyPropertyChanged.PropertyChanged when value changes.
public Int32 Hours { get; private set; }

The value converter will then convert the number into a visibility:

class VisibilityConverter : IValueConverter {

  public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture) {
    var hours = System.Convert.ToInt32(value);
    var visibleBelow = System.Convert.ToInt32(parameter);
    // Alternatively use Visibility.Collapsed to completely remove the circle.
    return hours <= visibleBelow ? Visibility.Visible : Visibility.Hidden;
  }

  public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture) {
    throw new NotImplementedException();
  }

}

Each Ellipse will then bind the Visibility to the Hours property using a ConverterParameter that identifies the hour of the Ellipse:

<Ellipse
  Visibility="{Binding Hours, Converter={StaticResource VisibilityConverter}, ConverterParameter=3}"/>
于 2013-09-26T07:27:49.550 回答
0

There are many ways to achieve this. Here is one you can do in raw XAML

  • Databind an ItemsControl to a collection of booleans generated by your view models - one bool for each hour represented.
  • Set ItemsControl.ItemTemplate to a template that includes an Ellipse with the same height and width and a border of [colour]
  • Use Actions / behaviors to set the Fill of the Ellipse to [colour] when the DataContext equals System.Boolean true

With this method, you will need to call raise PropertyChanged on the entire boolean collection each time one of them changes.

于 2013-09-26T10:13:13.003 回答