RSS

Category Archives: WPF

StringFormat missing for Bindings in Windows Phone 8.1

There is currently no possibility to use StringFormat in bindings if you develop a Windows Phone 8 project. With normal Windows applications this is done with the following XAML code.

<TextBox Text="{Binding Path=MyProperty, StringFormat='{}{0:N0} pcs.'}" />

You will miss this feature in Windows Phone projects. But there is a simple solution to overcome this problem. The solution is to use a class that inherits from IValueConverter. There you provide the logic to apply the formatting of the string.

public sealed class StringFormatConverter : IValueConverter 
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null)
        {
            return null; 
        }
        if (parameter == null)
        {
            return value;
        }
        return string.Format((string)parameter, value);
    }

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

In your XAML you can use this converter as follows:

<Grid>
    <Grid.Resources>
        <converters:StringFormatConverter x:Key="StringFormatConverter" />
    </Grid.Resources>
    <TextBox Text="{Binding Path=MyPropterty,
                            Converter={StaticResource StringFormatConverter},
                            ConverterParameter='{}{0:N0} pcs.'}" />
</Grid>
 
Leave a comment

Posted by on January 14, 2015 in C-Sharp, WP8.1, WPF

 

Tags: ,

WPF Printing Library v2.0

This project was moved to GitHub.

Introduction

Please refer to the first version of this library WPF Printing Library v1.0

What can be done until now using this library?

  1. Printing footer/header/recipient on every single page
    1. Decide whether the footer is print only on the last page
    2. Decide whether the header is print on every page, but not on the last page
  2. Printing the page count on every page
  3. Decide what has to be printed: e.g. header and no footer, no page count
  4. Print a new item on a new page if there is not enough page available
  5. Printing a customizable summary of all items at the end of the report

Resolved drawbacks from v1.0

  1. If an item is longer than the available space for printing items you will get an infinite loop.
  2. According standards of WPF, that a control is created only in the main thread, you cannot print in background(I will check that and try to fix it) Not possible
  3. Impossible to print to OneNote and XPS.
  4. Until now not possible to decide whether the footer is printed only on the last page according to that you also cannot decide whether a header is printed only on the first page.
  5. Only compatible with WPF (I will not change that).

Class Library

PrintAppendixes

The PrintAppendixes is a flag-enum that defines the parts that have to be printed. Here you can set up if you want to print only the page footer, page header, footer and header or all other possible combinations of all values. As you certainly know, flag enums can be combined. That means you can select only one value but also more of them by applying it with the binary operator |. PrintAppendixes pa = PrintAppendixes.Header | PrintAppendixes.Footer; This enum is used for the PrintOnPage attribute that has to be added on the PrintProcessor class.

IPrintPartDefinition

I have decided to remove the definition of the print parts that have to be printed from the PrintDimension constructor. The reason for that was, because there you could set the PrintAppendixes only once and this will hold for the whole document. I thought that it would be useful to define for every page whether the PrintAppendix should be print or not. Therefore I created an Attribute hierarchy that enables this. It is pretty cool and simple. Just set an attribute of your choice on your implementation of the PrintProcessor class. You have four types of attributes available:

  • PrintOnPage
  • PrintOnAllPages
  • ExcludeFromPage
  • ExcludeFromAllPages

I think the names are self-explanatory. Example: You want to print the footer only on the last page, but the header on every page except the last one. You achieve this by defining such a PrintProcessor class:

[PrintOnAllPages(PrintAppendixes.Header)]
[ExcludeFromPage(PrintAppendixes. Header, PrintPartDefinition.LastPage)]
[PrintOnPage(PrintAppendixes.Footer, PrintPartDefinition.LastPage)]
public abstract class TestPrintProcessor : PrintProcessor {}

That is all you need to do. Cool isn’t it? But what is happening if I define following attributes:

PrintOnAllPages(PrintAppendixes.Footer)]
[ExcludeFromPage(PrintAppendixes.Footer,1,4,5)]

If you write such a print part definition, that the footer gets only printed on page 2, 3, 6… If for a single page the ExcludeFrom and PrintOn is defined, than this print part will not be printed on this page. Now you might think that this is pretty cool, but it is very static and needs to be defined during coding. That’s right for the attribute aspect. But I have created an additional property PrintDefinition in the PrintProcessor class on which you can call the SetPrintAttribute(IPrintPartDefinition definition) method. Now you can change when to print which print part at any time.

PrintProcessor

The PrintProcessor class is the class of mayor interest. It is an abstract class based on the interface IPrintProcessor and provides all necessary methods and properties for creating a cool print with custom headers, footers etc. In order to do that you should override the corresponding methods (GetFooter, GetHeader,…). Note: If you define a header on page 2 and you do not provide a value for GetHeader() an exception gets raised. Not providing a header means that you do either return null or that you have not overwritten the method GetHeader().

Alternating the rows

An additional feature is to color the rows as you desire. To do that you can set a list of Brushes to the AlternatingRowColors property. But this is not enough: you have to enable the alternating coloring through the property IsAlternatingRowColor. If you just set IsAlternatingRowColor to true but do not set a value to AlternatingRowColors the default values, transparent and light gray, were used.

Break last item on new page

As you continue in printing it might be sometimes the case that you want to print the footer only on the last page. So it can be that all elements have been printed, but the footer does not fit on the last page. So we need a page break only to fit the footer on the last page. So we have the situation that on the last page the footer (and other PrintAppendixes) is printed. In order to avoid such an awkward situation you can set the property BreakLastItemIfLastPageWouldBeEmpty to.

Print result is not what you wanted

A very cool feature, for debugging reasons only is that you can enable coloring the print parts by setting ColorPrintPartsForDebug to true. This will color all the PrintAppendixes in such a way that you can see where space for a too large element is wasted. Demo ColorPrintPartsForDebug

Bulk print

Beginning from version 2.0 you can bulk print. This method takes a list of PrintProcessors that gets printed all at once.

Print direct to printer

Also a new feature for this version is that you can start printing and choose the printer from the print dialog, but also by direct printing to the printer. This is achieved by calling one overload of the Print method. You have two overloads available:

  • PrintDocument(printQueueName)
printer.PrintDocument(&quot;PDF-XChange Printer 2012&quot;);
  • PrintDocument(printQueueName, PrintServer)

This overload is used to print to a LocalPrintServer and set some settings to it.

PrintDimension

The next class that is of interest is the PrintDimension class. It provides all necessary information to paginate the document.

Here you can control the height that is reserved for each print part if it gets printed on the page. In addition I suggest to add some properties for the column width for the IPrintContent.Content panel. This is very useful because in many times this content panel is in tabular form. Change from v1.0: You cannot set the PrintAppendix in this class anymore. Instead you set it as attribute on the PrintProcessor class. The default contstructor initializes the Margin to {0,0,0,0}

Relative column position

Facts that your page size may vary from print to print you want stretch or shrink the print. In version 1.0 you set for every column in the IPrintContent.Content panel the width for each column. By setting UseRelativeColumnPosition to true you enable that the columns gets shrink a stretched as they have space. To define the width for a column you simply derive from PrintDimension and create some properties with a ColumnDimensionAttribute on it. The constructor takes a double representing the percentage that a column may fill up. As second parameter you can passeither ColumnDimensionType.Absolute or ColumnDimensionType.Relative relative. These two values are for defining whether the double value is an absolute width value for the column or like in the exaple below 50% of the page width. Example:

ColumnWidthAttribute

If you want to achieve columns that has exactly that width, than you write:

public class CustomPrintDimension: PrintDimension
{
    public CustomPrintDimension()
    {
        UseRelativeColumnPosition = true;
    }

    [ColumnDimension(.50,ColumnDimensionType.Relative)]
    public double WidthColumn1 { get; set; }

    [ColumnDimension(.15,ColumnDimensionType.Relative)]
    public double WidthColumn2 { get; set; }

    [ColumnDimension(.35,ColumnDimensionType.Relative)]
    public double WidthColumn3 { get; set; }
}

//usage

public override UIElement GetTable(out double tableHeaderHeight, out Brush borderBrush)
{
    Grid g = new Grid();
    borderBrush = Brushes.Gray;
   //for _printDimension.WidthColumn1 you will a value that repesents 50%
    //of the width of the page according the page orientation an page size.
    g.ColumnDefinitions.Add(new ColumnDefinition
        {Width = new GridLength(_printDimensions.WidthColumn1)});
    g.ColumnDefinitions.Add(new ColumnDefinition
       { Width = new GridLength(_printDimensions.WidthColumn2) });
    g.ColumnDefinitions.Add(new ColumnDefinition
        { Width = new GridLength(_printDimensions.WidthColumn3) });

Note: If you change the PageOrientation in your PrintProcessor class from Portrait, which is the default value, to Landscape you will get bigger values for WidthColumn1,WidthColumn2 and WidthColumn3 because the width of the printable area changed.

IPrintContent

This interface was refactored from ILineItem. It provides a single property only. With that property you can provide the content of the line. Unlike in the previous version you do not have to provide the height of the line. This gets computed automatically. NOTE: If the content is bigger than the remaining space of a page the element gets positioned automatically on a new page no matter if it has space or not.

public class TestPrintContent : IPrintContent
{
    private readonly int _item;
    public TestPrintContent(int item)
    {
        _item = item;
    }
    public Panel Content
    {
        get
        {
            var sp = new Grid();
            var textBlock = new TextBlock
                {Text = _item.ToString(),};
            sp.Children.Add(textBlock);
            return sp;
        }
    }
}

If you want to specify exactly the height of the content you can do this as follows:

public Panel Content
{
    get
    {
        var sp = new Grid();
        sp.Backgroud = Brushes.Red; //only to make the grid visible.
        sp.Height = 150;
        return sp;
    }
}

PrintProcessorBackground

As you might have seen in the PrintProcessor class there is a GetBackgroud() method that provides the background of the document. The class provides only methods for positioning the background on the document and the background element, of that the opacity can be set.

Sample C# project

You can download a complete working “Visual Studio 2012 project” that demonstrates my printing library by using this link: (Click here to download the sample project.). NOTE: please change the file format of the downloading document from .docx to .zip

 
35 Comments

Posted by on March 6, 2013 in Printing, WPF

 

Tags: ,

WPF Control DesiredSize has no value

It may be sometimes the case that you create controls via C# code. Especially when you create custom controls. Then you sometimes need the current control size. Well that is easy, may be thought.

Easily call control.DesiredSize.Width and control.DesiredSize.Height. The problem is that you will not get any values by calling Width and Height. This is because the control has not updated the value for the DesiredSize property.

One possible solution is to call the control.Mesure(someVeryBigSize). With that method you call the measurement procedure that calculates and updates the desired size of the control. As parameter you pass the size the control can allocate. If you want to know exactly the size of the control you want to call DesiredSize on you should consider to choose a very big size.

Only after that you have the possibility to retrieve a value for DesiredSize.Height and DesiredSize.Width.

 
Leave a comment

Posted by on January 9, 2013 in C-Sharp, WPF

 

Bind to WebBrowser’s Source Property

Unfortunately the Source property of the WebBrowser control is not a dependency property. Therefore it cannot be bound.
But there exists a workaround in order to bind a URI to a WebBrowser Control.
The workaround that exists is to create an attached property that can be bound and which changes reflect directly to the webbrowser’s source property.. This is done as follows:

public static readonly DependencyProperty BindableSourceProperty = DependencyProperty.RegisterAttached("BindableSource", typeof (string), typeof (WebBrowserUtility), new UIPropertyMetadata(null, OnBindableSourceChanged));

public static string GetBindableSource(DependencyObject obj)
{
    return (string)obj.GetValue(BindableSourceProperty);
}

public static void SetBindableSource(DependencyObject obj, string value)
{
    obj.SetValue(BindableSourceProperty, value);
}

private static void OnBindableSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    var browser = o as WebBrowser;
    if (browser == null)
        return;

    var uri = (string)e.NewValue;

    try
    {
        browser.Source = !string.IsNullOrEmpty(uri) ? new Uri(uri) : null;
    }
    catch (ObjectDisposedException) {}
}

This attached property can be bound as follows:

<WebBrowser Name="browse" Utilities:WebBrowserUtility.BindableSource="{Binding Path=MyStrigUrlProperty}" />

Nice isn’t it?

 
Leave a comment

Posted by on September 18, 2012 in C-Sharp, WPF

 

Tags:

ScrollViewer for ItemsControl

In a ItemsControl the ScrollViewer is not visible, not by setting ScrollViewer.HorizontalScrollBarVisibility to “Auto” nor by setting it to “Visible”.
The only solution is to wrap the ItemsControl into a ScrollViewer:

<ScrollViewer VerticalScrollBarVisibility="Auto">
     <ItemsControl ItemsSource="{Binding Path=MyList}"/>
</ScrollViewer>
 
Leave a comment

Posted by on September 18, 2012 in WPF

 

Tags:

XAML Designer NotSupportedException

Today I got following exception when I tried to display a XAML Control in the XAML-Designer offered from Visual Studio 2012.

An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework. This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.

The exception message intended to say that you have at least one referencing assembly that you have downloaded from the internet. By default, such assemblies are blocked by the Operating System. If you open the file’s preferences, you see following string at the bottom of the window:

This file came from another computer and might be blocked to help protect this computer:


Exactly about this fact Visual Studio warns you. If you trust the creator of that assembly, you can avoid this problem by clicking Unblock.

After that, you should clean your solutions Debug and Release folder in order to ensure that the right unblocked assemblies are copied in the solutions output directory.

Then Visual Studio should continue showing the XAML designer.

 
Leave a comment

Posted by on September 13, 2012 in Visual Studio, WPF

 

Tags: ,

Binding null-value of DateTime to DatePicker using an Attached Property

As you have seen in the post Binding null-value of DateTime to DatePicker  you could not bind a DateTime to a DatePicker without drawbacks. Because if you bind a non nullable DateTime, you will get after opening the DatePicker Popup the Calendar date range near the date 01.01.0001. To avoid that you can use the solution in the linked article or with my new solution using an AttachedProperty. With that one if the bound DateTime, which is not nullable, is DateTime.MinValue, the DatePicker shows on opening the Popup, on which you select a date, the actual date.

On the following picture you see left the situation if you bind a DateTime direct do a DatePicker, right the situation if you do it using my AttachedProperty.
image

<StackPanel Orientation"Horizontal" Height="30" VerticalAlignment="Top">
    <DatePicker Width="300" 
                SelectedDate="{Binding Path=SelectedDateTimeWhichIsNonNullable}" 
                WPFToolkit:CustomAttachedProperties.ShowNullWhenDateTimeMinValue="True">
    </DatePicker>
    <DatePicker Width="300" 
                SelectedDate="{Binding Path=SelectedDateTimeWhichIsNonNullable}">
    </DatePicker>
</StackPanel>

The logic for the AttachedProperty looks like:

public static class CustomAttachedProperties
{
    public static readonly DependencyProperty ShowNullWhenDateTimeMinValueProperty = 
                     DependencyProperty.RegisterAttached("ShowNullWhenDateTimeMinValue", 
                                        typeof (bool), 
                                        typeof (CustomAttachedProperties),
                                        new PropertyMetadata(default(bool),
                                        SetShowNullWhenDateTimeMinValueChanged));

    private static void SetShowNullWhenDateTimeMinValueChanged(DependencyObject d, 
                                           DependencyPropertyChangedEventArgs e)
    {
        DatePicker control = (DatePicker)d;
        if ((bool)e.NewValue)
        {
            control.SelectedDateChanged += OnSelectedDateChanged ;
        }
        else
        {
            control.SelectedDateChanged -= OnSelectedDateChanged ;
        }
    }

    public static void SetShowNullWhenDateTimeMinValue(UIElement element, bool value)
    {
        element.SetValue(ShowNullWhenDateTimeMinValueProperty, value);
    }

    private static void OnSelectedDateChanged (object sender, SelectionChangedEventArgs e)
    {
        UIElement control = (UIElement)sender;

        if ((bool)control.GetValue(ShowNullWhenDateTimeMinValueProperty))
        {
            var currentSelectedDate = ((DateTime?)control.GetValue(DatePicker.SelectedDateProperty));
            if (currentSelectedDate.HasValue && currentSelectedDate.Value == DateTime.MinValue)
            {
                //currently set DateTime.Now that the DatePicker opens the Popup with the current month
                control.SetValue(DatePicker.SelectedDateProperty, DateTime.Now);
                control.SetValue(DatePicker.SelectedDateProperty, null);
            }
        }
    }

    public static bool GetShowNullWhenDateTimeMinValue(UIElement element)
    {
        return (bool)element.GetValue(ShowNullWhenDateTimeMinValueProperty);
    }
}
 
3 Comments

Posted by on May 31, 2012 in C-Sharp, WPF

 

Tags: