views:

246

answers:

4

Hey,

I'm new in Silverlight and i am doing some tests. With my current test I try to display in real time the current Clipboard content. But there is a weird behaviors with this code :

namespace SilverlightTest
{
public partial class MainPage : UserControl
{
    private Timer _timer;

    public MainPage()
    {
        InitializeComponent();
        var dispatcher_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 5)};
        dispatcher_timer.Tick += new EventHandler(timer_Callback);
        dispatcher_timer.Start();
    }

    private void timer_Callback(object state, EventArgs eventArgs)
    {
        current_clip_board.Content = Clipboard.GetText();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        current_clip_board.Content = Clipboard.GetText();
    }
}
}

The button Event and the timer Event are suppose to do exactly the same action. But it doesn't ! The Button works fine and set the clipboard text into the label but the timer throw an exception :

Clipboard access is not allowed

The question is : why ? :)

Thanks.

PS : I would bet on a thread problem :p

+1  A: 

Have you tried this:

private void timer_Callback(object state, EventArgs eventArgs) 
{
    Dispatcher.Invoke(new System.Threading.ThreadStart(delegate()
    {
        current_clip_board.Content = Clipboard.GetText(); 
    }
} 

edit

After a quick search, it appears that Clipboard is only available in response to a user action see here and here.

In partial trust (the default mode for browser-hosted Silverlight-based applications), Silverlight also restricts clipboard access to its two key APIs GetText and SetText. These APIs can only be invoked from within a context that is determined by the Silverlight runtime to be in response to a user-initiated action. For example, clipboard access is valid from within a handler for a Click or KeyDown event. In contrast, clipboard access is not valid from a handler for Loaded or from a constructor, and access attempts throw exceptions.

Nate Bross
Dispatcher.Invoke generate a compilation error. BeginInvoke compiles but the same exception is generated by the same line :/ Any other ideas ?
Niklaos
+2  A: 

Clipboard access, in a partial trust (in-browser) Silverlight application (the scenario you're likely referring to above), is restricted. The GetText property is accessible only in scenarios that the Silverlight runtime determines were initiated by the user. Your example is perfect -- by a button click for example. A dispatch timer however is not user initiated, so the property throws an exception (this is especially important within the context of a in-browser application, which could be a big security hole if you could create a Silverlight application that just ran silently in the browser, watching the user's clipboard updates without their knowledge).

See this clipboard documentation for more details.

WPCoder
Thanks. Is there some ways to bypass this restriction ? I don't want a hack but, this might be an indispensable feature for the application that i want to build ...
Niklaos
@Niklaos: The only way around this restriction is to have the application installed as an out of browser app with elevated trust.
AnthonyWJones
Also note that the Silverlight clipboard is limited to only text.
WPCoder
+1  A: 

If your only option is to use a timer, then don't do it at all. The clipboad is a shared resource, and you're going to raise "cannot open clipboard" errors in other programs as they try to access the clipboard. i.e. user copies something from WinWord, WinWord tries to open the clipboard, but can't, because you've got it locked while you're examining it.

Chris Thornton
It's good to know ! I don't want to use a timer (it's quite ugly) but is there some other ways ? It's seems like Microsoft forgot the "ClipboardUpdated" event :p
Niklaos
No idea, as I don't know Silverlight. I've just got a lot of experience being at the other end of this sort of thing. Look for any sort of reference to Clipboard Viewer or WM_DrawClipboard, in the API docs. Also, understand that your GetText() call will cause a WM_RenderFormat message to be sent to the application that did the copying (if they use "Delayed Rendering" which most large apps do), so you'll be adding to your troubles that way as well, by pretty much guaranteeing that whatever you just tried to grab, will cause the providing app to want to open the clipboard again. And fail.
Chris Thornton
Microsoft did provide the clipboard updated message to native Win32 applications (WM_CLIPBOARDUPDATE). But, for a cross-platform Silverlight application, you don't have access to this message/functionality (especially within the context of a in-browser application, which would be a big security issue if you could write code that just sat silently in the browser, watching the user's clipboard updates without their knowledge).
WPCoder
+1  A: 

Just trigger Clipboard.ContainsText() instead of Text. The method ContainsText is allowed!

Lothar Grieb