This project is read-only.

Watermarking Pages

Mar 23, 2011 at 2:45 PM

Hi there,

Hope you will be able to help with this. I have a requirement to watermark each page of an xps document being displayed through the document viewer.

I've tried to do a work around using the Application Resources for the document viewer by adding a textblock after the border element of the fixed page viewer:

<Border Background="white" BorderBrush="#FF9D9D9D" BorderThickness="1" Margin="4" HorizontalAlignment="Center" VerticalAlignment="Center">
                                                   <doc:FixedPageViewer FixedPage="{Binding FixedPage}" 
                                                                     FixedPageSize="{Binding FixedPageSize}"
                                                                     FixedPageError="{Binding FixedPageError}"
                                                                     Scale="{Binding DesiredPageScale}">
                                                        <i:Interaction.Behaviors>
                                                            <doc:FixedPageAdorner Annotations="{Binding TextContainer.Annotations}" Selection="{Binding TextContainer.Selection}" />
                                                            <doc:NavigationBehavior TextContainer="{Binding TextContainer}" />
                                                        </i:Interaction.Behaviors>
                                                    </doc:FixedPageViewer>
                                                </Border>
                                                <TextBlock x:Name="txtWatermark1" Style="{StaticResource WatermarkStyle}" FontSize="64" FontWeight="Bold"  Foreground="#4F797979" VerticalAlignment="Center" HorizontalAlignment="Center">
                                                    <TextBlock.RenderTransform>
                                                        <RotateTransform Angle="-45"/>
                                                    </TextBlock.RenderTransform>                                                  
                                                </TextBlock>

Whilst this works ok, there are issues with the textblock not actually being part of the page when it comes to zooming etc.  Can you offer any help in implementing a better solution as per the watermark in evaluation versions.

Thanks

Colin.


Mar 23, 2011 at 11:42 PM

Hi Colin,

You need to provide a custom control template for the FixedPageViewer control. The watermark sample in the sample browser demonstrates this. Source code: http://documenttoolkit.codeplex.com/SourceControl/changeset/view/68817#1358606

 

 Koen

Mar 24, 2011 at 10:56 AM

Thanks kozw,

That certainly works better than my previous solution, I still have 1 issue in that the watermark itself needs to be dynamic based upon the current username.

I had managed to do this previously by binding the Style of the textblock to an empty style and then using:

  

 Dim style As Style = Application.Current.Resources("WatermarkStyle")
 style.Setters.Add(New Setter(TextBlock.TextProperty, _Username))

at application start-up to dynamically set the text. This however does not work with the control template. Any ideas would be appreciated

Colin.

 


Mar 24, 2011 at 1:13 PM

Managed to get this working now by setting the textblock style to {staticResource="....."} as opposed to {Binding="....."}

Thanks for the help

Colin.

Dec 8, 2011 at 11:46 PM
Edited Dec 8, 2011 at 11:47 PM

A few months later...

Adding a setter dynamically is working great, thank you for idea cthomson. But i would like to change watermark each time a user is clicking a button, after writing new watermark in a textbox.

The problem is we can't modify a setter. I removed it to re-add it with a new watermark text, but an error occurs. So, i think it's not possible...

Have you got an idea to do that ?

Dec 9, 2011 at 12:24 PM

You can use a viewmodel object that holds the current value of the Watermark text. When the text changes, you'll need to fire the INotifyPropertyChanged.PropertyChanged event. Then you need to make sure your object is in a resource collection and use the {StaticResource..} extension to bind to this watermarkt text in your template (as Colin suggested).

Dec 9, 2011 at 1:38 PM

I tested MVVM but my binding failed. I forgot something to associate my xaml binding with my datacontext but i'm a newbie. I'm sure you will find my error easily (thank you). This is a piece of code : 

<Style x:Key="WatermarkTextStyle" TargetType="TextBlock">
  <Setter Property="Text" Value="{Binding WaterMarkText}" />
</Style>

 

<!-- watermark -->
<Grid Style="{StaticResource WatermarkVisibilityStyle}" Width="{Binding FixedPageSize.Width, RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding FixedPageSize.Height, RelativeSource={RelativeSource TemplatedParent}}">
<i:Interaction.Behaviors>
<dte:ClipToBoundsBehavior />
</i:Interaction.Behaviors>
<Border Background="{StaticResource HighlightBrush}" Opacity=".8" HorizontalAlignment="Right" VerticalAlignment="Top" RenderTransform="1,1,-1,1,140,-140">
<TextBlock Style="{StaticResource WatermarkTextStyle}" FontWeight="Bold" FontSize="16" Foreground="White" Margin="128,12,128,12" />
</Border>
</Grid>


 
 
 
        public MainPage()
        {
            InitializeComponent();

            VM_MainPage MP = new VM_MainPage();
            this.DataContext = MP;
            MP.WaterMarkText = "toto";
            ....
 
    public class cNotifyPropertyChanged : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

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

        #endregion
    }

    public class VM_MainPage : cNotifyPropertyChanged
    {
        private string _WaterMarkText;
        public string WaterMarkText
        {
            get
            {
                return _WaterMarkText;
            }
            set
            {
                _WaterMarkText = value;
                OnNotifyPropertyChanged("WaterMarkText");
            }
        }
    }
 
 
 
 
 
Dec 12, 2011 at 10:48 PM

In fact, it seems not possible with Silverlight 4, but possible with Silverlight 5 with something like this :

<nViewer:VM_DocViewer x:Key="DocViewer"/>
<Style x:Key="WatermarkTextStyle" TargetType="TextBlock">
<Setter Property="Text" Value="{Binding Source={StaticResource DocViewer},Path=WaterMarkText}" />
</Style>
More Info : http://www.kunal-chowdhury.com/2011/05/binding-on-style-setter-in-silverlight.html
But this evening, the question is : should we continue with Silverlight ? Not sure, and i'm sad...
Dec 13, 2011 at 10:23 AM

When you add your VM_MainPage instance to a resource dictionary you can bind to the properties of this class using the StaticResource markup extension. You can't use the DataContext of a FixedPageViewer, it's reserved for FixedPage instances.

So something like this should work;

In your constructor:

this.Resources.Add("MP", MP);

and then in the XAML

<TextBlock DataContext="{StaticResource MP}" Text="{Binding WaterMarkText}" />


This works fine in both Silverlight 4 and 5. Silverlight 5 has been released recently, you can use Document Toolkit in Silverlight 5.


- koen

Dec 13, 2011 at 3:37 PM
Edited Dec 13, 2011 at 4:05 PM

Thank you kozw, it's working great !

i had to replace this.Resources by Application.Current.Resources, may be because i'm using a childwindow, i don't know. This is the code below :

Page load :

VM_WaterMark WaterMark = null;

if (Application.Current.Resources["MyWaterMark"] == null)
{
    WaterMark = new VM_WaterMark();
    Application.Current.Resources.Add("MyWaterMark", WaterMark);
}
else
{
    WaterMark = Application.Current.Resources["MyWaterMark"] as VM_WaterMark;
}

InitializeComponent();

this.Loaded += (o, e) =>
{
    WaterMark.Text = WaterMark.Text; //OnNotifyPropertyChanged

 

Change WaterMark button :

private void ChangeWatermark_Click(object sender, RoutedEventArgs e)
{
    VM_WaterMark WaterMark = Application.Current.Resources["MyWaterMark"] as VM_WaterMark;

    if (txWatermark.Text == string.Empty)
        WaterMark.Text = null;
    else
        WaterMark.Text = txWatermark.Text.Trim();
}

VM :

public class VM_WaterMark : INotifyPropertyChanged
{
    private string _Text;
    public string Text
    {
        get
        {
            return _Text;
        }
        set
        {
            _Text = value;
            _Visible = (_Text != null);
            OnNotifyPropertyChanged("Text");
            OnNotifyPropertyChanged("Visible");
        }
    }

    private bool _Visible;
    public bool Visible
    {
        get
        {
            return _Visible;
        }
    }
}

XAML :

<StackPanel DataContext="{StaticResource MyWaterMark}" Visibility="{Binding Visible, Converter={StaticResource VisibilityConverter}}">
    <Grid Width="{Binding FixedPageSize.Width, RelativeSource={RelativeSource TemplatedParent}}" Height="{Binding FixedPageSize.Height, RelativeSource={RelativeSource TemplatedParent}}">
        <i:Interaction.Behaviors>
            <dte:ClipToBoundsBehavior />
        </i:Interaction.Behaviors>
        <Border Background="{StaticResource HighlightBrush}" Opacity=".8" HorizontalAlignment="Right" VerticalAlignment="Top" RenderTransform="1,1,-1,1,140,-140">
        <TextBlock Text="{Binding Text}" FontWeight="Bold" FontSize="16" Foreground="White" Margin="128,12,128,12" />
        </Border>
    </Grid>
</StackPanel>