0

In a current project, I have a list of objects. And 2 of the properties are of type string[].

Currently I'm able to display the amount of items with their primary identifier. But alongside that I want to display all the different strings in the designated string[].

The class looks like this:

public class TimeStamp
{
    public int ID { get; set; }
    public string[] DaysOfWeek { get; set; }
    public string[] HoursOfDay { get; set; }
}

In my page, I have the following (working as described above)

    <ListView x:Name="listboxFolder1"  Grid.Row="2" Margin="5" Grid.ColumnSpan="4" 
        ItemsSource="{Binding}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Border BorderBrush="Blue" Margin="3" Padding="3" BorderThickness="2" CornerRadius="0 25 0 25" Background="Beige" HorizontalAlignment="Stretch">
                    <StackPanel Orientation="Horizontal">
                        <Image Margin="10" Width="50" Height="50" Stretch="Fill" Source="/Images/watch.png">
                            <Image.BitmapEffect>
                                <DropShadowBitmapEffect />
                            </Image.BitmapEffect>
                        </Image>
                        <StackPanel Orientation="Vertical" VerticalAlignment="Center">
                            <TextBlock Text="{Binding ID}"/>
                            <TextBlock Text="{Binding DaysOfWeek}"/>
                        </StackPanel>
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

And for completion, the setting of the binding:

    static List<iBackupModel.Models.TimeStamp> mySchedules { get; set; }
    public Scheduler()
    {
        InitializeComponent();
        listboxFolder1.ItemsSource = Home.mySettings.TimeStamps;
    }

But the DaysOfWeek gets displayed like: String[]-matrix.

I would like it to be something like "monday|friday|sunday".

If it would be possible to match this with a fixed set (in this case all the weekdays) and put a strikethrough through all the missing items, that would be great, but I would already be thankful for the first.

Is this possible?

For both the first and the second option?

Any help is more then welcome. Thanks in advance.

4 Answers 4

3

The problem is that you are binding the Text property of your TextBlock to a string[] instead of a string.

What happens internally is that WPF calls the ToString() method on the DaysOfWeek string array, which results in "System.String[]".

What you want is to bind to string.Join("|", DaysOfWeek }).

There are various ways to do this. A highly recommended way would be to create a "view model" that holds the data you actually want to display rather than the data that, say, came out of a database or some other kind of model.

So, you could create a TimeStampViewModel, which looks like this:

public class TimeStampViewModel
{
    public int Id { get; set; }
    public string DaysOfWeek { get; set; }
    public string HoursOfDay { get; set; }

    public TimeStampViewModel(int id, string[] daysOfWeek, string[] hoursOfDay)
    {
        Id = id;
        DaysOfWeek = string.Join("|", daysOfWeek);
        HoursOfDay = string.Join("|", hoursOfDay);
    }
}

Then, instead of binding to TimeStamp objects, you bind to TimeStampViewModel objects, which you create in your code behind class, like so:

TimeStampViewModels = timeStamps
    .Select(x => new TimeStampViewModel(x.Id, x.DaysOfWeek, x.HoursOfDay))
    .ToList();

This assumes you have a property public List<TimeStampViewModel> TimeStampViewModels { get; set; } in your code-behind.

If you want to understand more about view models in general, I recommend you read up on the Model-View-ViewModel (MVVM) pattern. Here as an article published by Microsoft to get you started. MVVM is considered by many to be a best practice for programming in WPF (and other XAML-based frameworks).


To handle your "extra credit" question regarding the strikethrough, that's going to be a bit more tricky. You would need to modify your view model to something like this:

public class TimeStampViewModel
{
    public int Id { get; set; }
    public List<OptionalDayOfWeek> DaysOfWeek { get; set; }
    public string HoursOfDay { get; set; }

    public TimeStampViewModel(int id, string[] daysOfWeek, string[] hoursOfDay)
    {

        Id = id;
        DaysOfWeek = 
            new[] { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }
            .GroupJoin(daysOfWeek, day => day, dayOfWeek => dayOfWeek, (day, matches) => new OptionalDayOfWeek { DayOfWeek = day, IsAvailable = matches.Any() })
            .ToList();
        HoursOfDay = string.Join("|", hoursOfDay);
    }
}

public class OptionalDayOfWeek
{
    public string DayOfWeek { get; set; }
    public bool IsAvailable { get; set; }
}

Meanwhile, your XAML would need to present the days of week inside something like an ItemsControl, where each item is bound to a OptionalDayOfWeek. Then you could use an IValueConverter to determine whether the TextDecorations should include a Strikethrough or not. (Sorry, I don't have time to write this part at the moment, but hopefully that's enough of a hint to get started.)

Sign up to request clarification or add additional context in comments.

2 Comments

I have considered this solution, but it seems at least unlogical to place another class in front of the model. And at every update, there is at least 2 objects that need to be updated (or 1 needs to be recalculated). But if I went with the approach, is there an idea for the second question?
I added some more content to my answer to begin to address the strikethrough problem. As for why bother with a view model? View models are not always necessary, but the larger your project becomes, the more helpful it is to create a hard separation between what needs to be stored in the database and what needs to be stored on screen. Reading up on the MVVM pattern would help make this more clear.
0

I basically agree with devuxer on his approach. On the other hand, if you wish to keep your model class, the easiest way to cover your second question will be adding converter from string array to TextDecorations.

[ValueConversion(typeof(string[]), typeof(TextDecorations))]
public class DecorationsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var source = value as string[];
        if (source == null)
            return DependencyProperty.UnsetValue;

        return source.Contains(parameter as string) ? null : TextDecorations.Strikethrough;
    }

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

And changing the ListView to use that converter.

<ListView x:Name="listboxFolder1"  Grid.Row="2" Margin="5" Grid.ColumnSpan="4">
    <ListView.Resources>
        <local:DecorationsConverter x:Key="DecorationsConverterKey"/>
    </ListView.Resources>
    <ListView.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Blue" Margin="3" Padding="3" BorderThickness="2" CornerRadius="0 25 0 25" Background="Beige" HorizontalAlignment="Stretch">
                <StackPanel Orientation="Horizontal">
                    <Image Margin="10" Width="50" Height="50" Stretch="Fill" Source="/Images/watch.png">
                        <Image.BitmapEffect>
                            <DropShadowBitmapEffect />
                        </Image.BitmapEffect>
                    </Image>
                    <StackPanel Orientation="Vertical" VerticalAlignment="Center">
                        <TextBlock Text="{Binding ID}"/>
                        <TextBlock>
                            <Run Text="Sunday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Sunday}"/>
                            <Run Text="|"/>
                            <Run Text="Monday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Monday}"/>
                            <Run Text="|"/>
                            <Run Text="Tuesday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Tuesday}"/>
                            <Run Text="|"/>
                            <Run Text="Wednesday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Wednesday}"/>
                            <Run Text="|"/>
                            <Run Text="Thursday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Thursday}"/>
                            <Run Text="|"/>
                            <Run Text="Friday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Friday}"/>
                            <Run Text="|"/>
                            <Run Text="Saturday"
                                 TextDecorations="{Binding DaysOfWeek, Converter={StaticResource DecorationsConverterKey}, ConverterParameter=Saturday}"/>
                        </TextBlock>
                    </StackPanel>
                </StackPanel>
            </Border>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

2 Comments

This is exactly what I needed, thank you for this answer.
You are welcome. It's off topic but I think it is better to change type of DaysOfWeek property from string array to array of System.DayOfWeek enumeration for safer matching.
0

You want to display DaysOfWeek as a text in a TextBlock. DaysOfWeek is a string array not a string so it will be not shown as you expected. You have to convert to a string and you can specify the format in the conversion function. You have to ways to convert your string array to a formatted string in WPF

First solution: The nicer but complex way

public class WeekDaysFormatConverter : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value != null && value is string[])
        {
            return string.Join("|", value as string[]);
        }

        return value;
    }

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

And apply it:

<Window.Resources>
    <local:WeekDaysFormatConverter x:Key="WeekDaysFormatConverter" />
</Window.Resources>
...
<TextBlock Text="{Binding DaysOfWeek Converter={StaticResource WeekDaysFormatConverter}}"/>

Second solution: simply use a property to specify the format:

public class TimeStamp
{
    public int ID { get; set; }
    public string[] DaysOfWeek { get; set; }
    public string[] HoursOfDay { get; set; }

 public string DaysOfWeekFormatted
    {
        get
        {
            return DaysOfWeek != null ? string.Join("|", DaysOfWeek) : string.Empty;
        }
    }
}

And apply it:

<TextBlock Text="{Binding DaysOfWeekFormatted}"/>

Comments

0

You can modify the class as like the following:

public class TimeStamp
    {
        private string _HourList;
        private string _DayList;
        private string[] _DaysOfWeek;
        private string[] _HoursOfDay;
        public string[] HoursOfDay
        {
            get { return _HoursOfDay; }
            set
            {
                _HoursOfDay = value;
                _HourList = String.Join("|", value);
            }
        }
        public int ID { get; set; }
        public string[] DaysOfWeek
        {
            get { return _DaysOfWeek; }
            set
            {
                _DaysOfWeek = value;
                _DayList = String.Join("|", value);
            }
        }
        public string DayLis
        {
            get { return _DayList; }
        }
        public string HourList
        {
            get { return _HourList; }
        }
    }

The advantages of defining the class like this:

whenever you assign value to string array DaysOfWeek it will automatically creates a string DayList in that all array elements ware combined together with a delimiter |, Since DayList is a read only property you cannot assign value to it. you will get the value from this property as well at the time of binding

hence your xamal markups will be like the following:

 <StackPanel Orientation="Vertical" VerticalAlignment="Center">
      <TextBlock Text="{Binding ID}"/>
      <TextBlock Text="{Binding DayLis}"/>
 </StackPanel>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.