Silverlight button on mainpage, linked to command, never calling the method - wpf

I'm brand new to Silverlight and I'm in the deep end a little over my head so I'm probably missing something really obvious. I'm working on an image editor and I have a button on my main page that is supposed to rotate images or text on my canvas. The button however isn't calling my rotate method. EDIT: It is now.
Here's all the code I've written related to the button
MainPage.xaml
<Button Command="{Binding Path=Project.RotateCWElementCommand}"..../>
Project.cs -
#region properties
public ICommand RotateCWElementCommand { get; set; }
#endregion
#region methods
public Project(int siteID)
{
this.RotateCWElementCommand = new DelegateCommand(RotateCWElement, CanRotateCWElement);
}
private void RotateCWElement(object param)
{
FrameworkElement element = this.SelectedElement;
RotateTransform cwRot = new RotateTransform();
cwRot.Angle = 90;
cwRot.CenterX = element.ActualWidth * 0.5;
cwRot.CenterY = element.ActualHeight * 0.5;
element.RenderTransform = cwRot;
}
#end region
#region Command conditions
private bool CanRotateCWElement(object param)
{
return true;
}
#endregion
The problem now is that it will only rotate once and some image quality also appears to be lost. The images move strangely when I click and drag them, and sometimes when I click the full image quality returns.
If anybody has any ideas about this it'd be great.

It sounds like the Button.DataContext does not contain a property called Project.RotateCWElementCommand
Verify that your Button's DataContext has a property called Project, and that Project has a property called RotateCWElementCommand

The output window in Visual Studio can be very helpful for finding issues with your bindings in Silverlight and will help clarify if Rachel's suggestion is the problem.

Related

Show hidden WPF elements in Visual Studio designer

As opposed to this, does anybody has figured out a way to show all hidden elements while working in Visual Studio designer(or Blend)?
It's anti-productive to constantly change the default visibility property of elements to be able to see them while editing Xaml files.
After researching, I found this. So here's a tested solution that can be implemented in the view model :
//Declare default Visibility values
private Visibility _processBarVisibility = Visibility.Hidden;
private Visibility _buttonVisibility = Visibility.Hidden;
public ViewModel()
{
//In constructor, override Visibility values if in design mode
DependencyObject dep = new DependencyObject();
if (DesignerProperties.GetIsInDesignMode(dep))
{
_processBarVisibility = Visibility.Visible;
_buttonVisibility = Visibility.Visible;
}
}

Update WPF Window Asynchronously

I am creating a simple WPF app that when you click on a button it runs through a few steps like copy the file to a new location, convert the file then it copies the new file back to the original location.
The steps are working fine but I would like to have the WPF window update to which step it is on and hide the button while it is running.
The window only updates once it has finished running my code. I think I used to be able to do this on classic forms with me.refresh but this doesn't work on WPF.
Is something I can do to update the window after each step is complete?
Thank you
Button1.Visibility = Windows.Visibility.Hidden
FileCopy("C:\Test.xsf", AppPath & "\Convert\test.xsf")
Image7.Visibility = Windows.Visibility.Hidden
Image3.Visibility = Windows.Visibility.Visible
Program.StartInfo.FileName = xDefs
Program.StartInfo.Arguments = "/q"
Program.Start()
Program.WaitForExit()
Image5.Visibility = Windows.Visibility.Visible
FileCopy("AppPath & "\Convert\test.csv, "C:\Test.csv")
Button1.Visibility = Windows.Visibility.Visible
In order to update the UI while your program is busy, you'll need to use the Dispatcher class to add your update request onto the UI message queue. Take this synchronous example:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
ConvertFile(filePath);
CopyFileBack();
}
We could use the Dispatcher class to break this up and feed messages back to the UI in between tasks:
public void DoWorkWithFile(string filePath)
{
CopyFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied" });
ConvertFile(filePath);
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Converted" });
CopyFileBack();
RunOnUiThread((Action)delegate { SomeUiTextBlock.Text = "Copied back" });
}
private object RunOnUiThread(Action method)
{
return Dispatcher.Invoke(DispatcherPriority.Normal, method);
}
I know this is a VB.NET tagged question but I'll just go ahead and share a C# solution. I hope you know enough of it to port it to VB. This is the first time and posting anything to stackoverflow, if it solves your problem please mark it as the answer :-)
You must first know a thing or two (actually a lot more) on data binding. You basically create a view model, define the property that changes with time and bind this to the window. In this case you must define a value to keep track of the current operation and let the button control.
Disclaimer, I wrote this in notepad and haven't tested it on visual studio. Be on the lookout for typos.
using System.ComponentModel;
namespace FileConverter
{
//define the various states the application will transition to
public enum OperationStatus
{
CopyingFileToNewLocation
ConvertingFile,
CopyingFileToOriginalLocation
OperationCompelete
}
//Defines the view model that shall be bound to the window.
//The view model updates the UI using event notifications. Any control that had enabled
//binding will get updated automatically
public class ViewModel : INotifyPropertyChanged//This interface defines an event used to raise an event and notify subscribers of a changed in data
{
private OperationStatus _FileConvertionStatus;
public event PropertyChangedEventHandler PropertyChanged;
public OperationStatus FileConvertionStatus
{
get
{
return _FileConvertionStatus;
}
set
{
_FileConvertionStatus=value;
//Notify all UIElements / objects that had subscribed to this property that it has changed
RaisePropertyChanged(this,"FileConvertionStatus");
}
}
public void RaisePropertyChanged(object sender,string propertyName)
{
//check if there is any object that had subscribed to changes of any of the data properties in the view model
if(PropertyChanged!=null)
PropertyChanged(sender,new PropertyChangedEventArgs(propertyName));
}
public void StartFileConvertion(string filePath)
{
//Any time we change the property 'FileConvertionStatus', an event is raised which updates the UI
this.FileConvertionStatus=OperationStatus.CopyingFileToNewLocation;
StartCopyingToNewLocation(); //call your copying logic
this.FileConvertionStatus=OperationStatus.ConvertingFile;
StartFileConvertion(); //call your conversion logic
this.FileConvertionStatus=OperationStatus.CopyingFileToOriginalLocation();
CopyFileToOriginalLocation(); //...
this.FileConvertionStatus=OperationStatus.OperationCompelete;
}
}
}
//Now for the UI section
In the constructor of the window, you must bind the window to the view model right after this window has been initialized
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ViewModel vm=new ViewModel();
//setting the data context property the window implicitly binds the whole window to our view model object
this.DataContext=vm;
string filePath="c:\file.txt";
//start the file manipulation process
vm.StartFileConvertion(filePath);
}
}
//Next step we need to bind the button to the 'FileConvertionStatus' property located in the view model. We don't bind the button to the whole view model, just the property that it's interested in. Having bound the window to the view model in the previous code, all child elements get access to the public properties of this view model (VM from now on). We do the property binding in XAML
..Button x:Name="btnStartFileProcessing" Enabled="{Binding FileConvertionStatus}"...
We're almost there. One this is missing. You'll notice that the 'Enabled' property is a Boolean value. The 'FileConvertionStatus' property is enum. Same way you can't assign an enum to a Boolean directly, you need to do some convertion. This is where converters come in.
Converters allow you to define how one property can be converted to a different one in XAML. In this case we want the button to be enabled only when file conversion is successful. Please do some reading into this.
Create a class as shown below:
using System.Windows.Data;
namespace FileConverter
{
public class OperationStatusToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
OperationStatus status=(OperationStatus)value;
switch(status)
{
case OperationStatus.OperationCompelete:
return true; //enable the button when everything has been done
default:
return false;//disable the button as the file processing is underway
}
}
public object ConvertBack(object value, Type targetType,object parameter,System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Next step is to define the converter in XAML code. Think of this as initializing it though it can't be further from the true :-). Its more of importing the namespace into the xaml.Put the code below in the App.XAML file. Doing such declaration in the App.XAML file makes the code visible globally.
xmlns:MyConverters="clr-namespace:FileConverter"
In the Application.Resources XAML tag, declare the converter as shown below
<Application.Resources>
<MyConverters:OperationStatusToBooleanConverter x:Key="OperationStatusToBooleanConverter"/>
</Application.Resources>
Final Step
Redo the binding code in the button to include the converter.
...Button Enabled="{Binding FileConvertionStatus,Converter={StaticResource OperationStatusToBooleanConverter}}" x:Name="btnStartFileProcessing" ...
Please note that I haven't thread-optimized this code, the main problem is that all work is being done on the UI thread which can lead to the window hanging if an operation takes long.
The amount of work needed to properly set the binding up as per MVVM code standards is a lot. It might seem like an over-kill and at times, it actually is. Keep this in mind though, once the UI gets complex MVVM will definitely save the day due to the separation of concerns and binding strategies.

Trigger repaint of WPF Button control from external thread

I am having some issues with WPF not fully repainting a button control when the button is changed from another thread, and I am not sure how to force it to do a full repaint.
The situation is that on receipt of a message (via WCF - but the source isn't important, except that it is an external thread) I update the foreground color and visibility of a button. WPF immediately repaints the text on the button face, but the surface of the button is not repainted until I click anywhere on the application.
I have tried calling InvalidateVisual() on the button, but that did not help. I think that I am not understanding how a background thread can force a repaint. But the frustrating thing is that something is getting repainted and every other control I am using (text and image controls) are also getting properly repainted when I update them from my same message receipt.
I have now tried sending an empty message to the Dispatcher of the application via Invoke(), but no luck there either.
So I am looking for tips on how to tell WPF that it needs to update the rest of the button and not just the text.
Edit
This is a rough skeleton of my program. Note that I have wrapped the button in a class as there is other related state information I am keeping with it.
class myButton
{
Button theButton
void SetButton()
{
theButton.Forground = a new color
}
}
main
{
myButton.theButton = (Button on WPF canvass)
RegisterCallback( mycallbackFunction) with WCF client endpoint
}
void myCallbackFunction(message)
{
if message has button related stuff, call myButton.SetButton
}
Edit 2
Solved my problem .. it was actually a conflict between a "CanExecute" method and setting the buttons attributes in the callback. Once I removed the "CanExecute" function it all worked.
Setting properties on the button itself from code, especially another thread/callback, is an entrance to a painful world of inconsistent states.
What you should do is bind your button's properties to properties in your code, and then have your callback change those external properties.
I know the code you posted was kind of a mock up for what you actually want to do in your program, and I couldn't really follow your logic, but here's a complete program that operates similarly to your example and shows what I'm talking about. Let me know if I've missed the mark.
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
///
public class MyButton : INotifyPropertyChanged
{
private Button _theButton;
public Button TheButton
{
get { return _theButton; }
set
{
_theButton = value;
//set text binding
Binding textBind = new Binding("Text");
textBind.Source = this;
textBind.Mode = BindingMode.OneWay;
_theButton.SetBinding(Button.ContentProperty, textBind);
//set color binding
Binding colorBind = new Binding("Brush");
colorBind.Source = this;
colorBind.Mode = BindingMode.OneWay;
_theButton.SetBinding(Button.ForegroundProperty, colorBind);
NotifyPropertyChanged("TheButton");
}
}
public void Set(string text, Brush brush)
{
this.Text = text;
this.Brush = brush;
}
private string _text;
public string Text
{
get { return _text; }
set { _text = value; NotifyPropertyChanged("Text"); }
}
private Brush _brush;
public Brush Brush
{
get { return _brush; }
set { _brush = value; NotifyPropertyChanged("Brush"); }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
internal void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
public partial class MainWindow : Window
{
MyButton _myButton = new MyButton();
public MainWindow()
{
InitializeComponent();
//button1 is defined in XAML markup
_myButton.TheButton = this.button1;
//or else this could be your callback, same thing really
Thread t = new Thread(SetButton);
t.Start();
}
void SetButton()
{
_myButton.Text = "wo0t!";
_myButton.Brush = Brushes.Red;
//or
_myButton.Set("giggidy!", Brushes.Yellow);
}
}
}
Note that binding your Button properties in XAML is much less ugly, but then we're getting into UserControls and DataContexts which is another topic. I would look at inheriting the Button class to implement the features you want.
I recommend reading the article (Build More Responsive Apps With The Dispatcher) from MSDN magazine that describes how WPF works with the Dispatcher when using BackgroundWorker.
As per my edit, I had conflict between the buttons CanExecute binding in the XAML and me setting the background color in the callback. I didn't really need the CanExecute, so getting rid of that solved my problem.

XAML Without WPF - Animations

I am trying to use XAML completely outside WPF, in particular inside an XNA application. So far, I have managed (quite easily, I am surprised to admit) to load some data inside my XNA application from a XAML file. The problems start when I decided that I wanted to animate one of the properties of my class...Nothing happens :(
Here is the main class I load from the XAML file:
[ContentPropertyAttribute("Animation")]
public class Test : FrameworkContentElement
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
Here is the XAML file:
<l:Test xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="360"
Duration="00:00:10.0"/>
</a1:Storyboard>
</l:Test>
And here is the loading and animation launching (attempt):
Test test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
test.Animation.Begin(test);
I am dying of curiosity :)
Although XAML is independent of WPF, the visual elements aren't. In particular, animation and layout are part of WPF, and depends on the WPF plumbing being present -- through an Application object, a PresentationSource such as a HwndSource, the XBAP PresentationHost.exe, etc.
So you can read in your XAML and get an object graph of a Test object with a child Storyboard object, but that Test object isn't hooked up to the animation or layout engines until it's placed in a WPF context. All that the XAML gets you is a dumb in-memory object graph: it's WPF, not XAML, that makes the objects "live."
So as Ben says, you'll probably end up needing to "push or prod" the animation yourself. I'm not aware of any documentation on how to do this, but from poking around in Reflector, it looks like the key API is Storyboard.SeekAlignedToLastTick, of which the docs say:
Values are immediately updated to
reflect the changes due to
SeekAlignedToLastTick, even though the
screen does not reflect these changes
until the screen updates.
Notice that second clause. Normally, WPF handles the updating of the screen as visual object values change. If you're not using WPF, then it's up to you to read the changed values out and redraw the screen accordingly: you don't have the WPF layout manager to handle it for you.
Finally, please note I haven't tested whether SeekAlignedToLastTick will work in an environment without the WPF plumbing loaded. It sounds like it should, because it doesn't care whether it's WPF or user code which is driving the clocks, but I can't make any promises... though I admit you've got me curious!
UPDATE: I've given this a quick go, and it does seem to work. Here's a demo of hosting an animation within Windows Forms (in this case using a plain ol' Windows Forms timer, but in XNA I guess the framework will provide a game timer for you -- didn't try that because I don't know XNA). Assume you have a vanilla Windows Form with a timer (timer1) and a label (label1), and that the project references the WPF assemblies.
First, my simplified version of your class:
[ContentProperty("Animation")]
public class Fie : DependencyObject
{
public double Test
{
get { return (double)GetValue(TestProperty); }
set { SetValue(TestProperty, value); }
}
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register("Test", typeof(double), typeof(Fie),
new FrameworkPropertyMetadata(0.0));
public Storyboard Animation { get; set; }
}
Now, the WPF code to load one of these babies from XAML and begin the animation:
private Fie _f;
private DateTime _startTime;
public Form1()
{
InitializeComponent();
string xaml =
#"<local:Fie xmlns:local=""clr-namespace:AnimationsOutsideWpf;assembly=AnimationsOutsideWpf""
xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty=""Test""
From=""0""
To=""360""
Duration=""00:00:10.0""/>
</Storyboard>
</local:Fie>";
_f = (Fie)XamlReader.Load(XmlReader.Create(new StringReader(xaml)));
Storyboard.SetTarget(_f.Animation, _f);
_f.Animation.Begin();
_startTime = DateTime.Now;
timer1.Enabled = true;
}
Note that I had to set the storyboard's target to be the XAML object I'd just loaded. This doesn't happen automatically. I tried doing this with Storyboard.TargetName in the XAML, but that didn't seem to work -- you may have more luck.
The final lines are just setup for the timer callback:
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan sinceStart = DateTime.Now - _startTime;
_f.Animation.SeekAlignedToLastTick(sinceStart);
label1.Text = _f.Test.ToString();
}
I've stored the start time of the animation, and used that to calculate how far into the animation we are. WinForms timers are a bit crude, but this suffices for proof of concept; no doubt XNA will have something better. Then I call Storyboard.SeekAlignedToLastTick, which updates the animated values. Nothing displays automatically because my XAML object isn't hooked up for display, but I can check its Test property and verify that it is indeed animating. In reality, I'd use this to update the position or orientation of whatever XNA visual element the XAML object represented.
Just for reference, I will now document how I managed to make this work with XNA. Thanks to itowlson for providing the missing link: otherwise I had to create an empty Application with an invisible Window...
We define the class with its animation in XAML (notice the xmlns directives):
<l:Test
xmlns:l="clr-namespace:XAMLAndXNA;assembly=XAMLAndXNA"
xmlns:a1="clr-namespace:System.Windows.Media.Animation;assembly=PresentationFramework"
xmlns:a2="clr-namespace:System.Windows.Media.Animation;assembly=PresentationCore"
Text="Testo" Position="55,60" Color="0,255,255,255">
<a1:Storyboard>
<a2:DoubleAnimation a1:Storyboard.TargetProperty="Rotation"
From="0"
To="6.28"
Duration="00:00:2.0"
RepeatBehavior="Forever"/>
</a1:Storyboard>
</l:Test>
The "code-behind" class Test is the following:
[ContentPropertyAttribute("Animation")]
public class Test : DependencyObject
{
public string Text { get; set; }
public Vector2 Position { get; set; }
public Color Color { get; set; }
public Storyboard Animation { get; set; }
public static DependencyProperty RotationProperty =
DependencyProperty.Register("Rotation", typeof(double), typeof(Test), new PropertyMetadata(0.0));
public double Rotation { get { return (double)GetValue(RotationProperty); } set { SetValue(RotationProperty, value); } }
}
In the Initialize function of the XNA Game class we deserialize our xaml file and start the animation:
test = XamlReader.Load(new XmlTextReader("SpriteBatchStuff.xaml")) as Test;
Storyboard.SetTarget(test.Animation, test);
test.Animation.Begin();
The Update function takes as input a GameTime, which offers the TotalGameTime field that stores the TimeSpan of the amount of time passed since the app launch: that is exactly what a Storyboard needs to tick:
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
test.Animation.SeekAlignedToLastTick(gameTime.TotalGameTime);
base.Update(gameTime);
}
In the draw method we can just draw some text using the Rotation property, which will now be correctly animated:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load<SpriteFont>("font"), test.Text, test.Position, test.Color, (float)test.Rotation, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
spriteBatch.End();
base.Draw(gameTime);
}
Outside of the normal loop of a WPF application, I doubt there is any way to drive the animation. There may be some class you can push or prod to drive them, but it is likely sealed.
You will probably wind up building your own animation execution engine running on another thread and ensuring the updates happen on your UI thread, which means either finding a way to reuse the Dispatcher or recreating something similar.
This MSDN article may provide some useful information in this endeavor
It's an interesting project... I'd be curious to hear if you succeed!
Wow, this is pretty awesome! Unfortunately, it will likely come down to some "update" type of call that is being made in some internal API. And if you don't call it, the animation won't animate ... much like if an XNA game doesn't have the Update method called.
I would very much like more info on how you're doing this and what level of success you're finding. You should write a blog post/article somewhere :-)

How to update Source property of MediaElement and start playback in Silverlight 3.0

I'm writing a small Silverlight media player application. In the top of the page i have an horizontal listbox with listboxitems. The listbox is bound to a datasource containg an object I've created called ContentItem. The ContentItem is defined like this:
public class ContentItem
{
public string CoverUrl { get; set; }
public string ResourceUrl { get; set; }
public ContentItem()
{
}
}
I also have an Media element:
<MediaElement x:Name="MediaBox" Source="http://localhost/repository/FighterPilot.wmv" Stretch="Fill"/>
So my thaught was, when the user chooses a new ContentItem from the listbox, I want to change the source of the MediaElement and start playing the new ContentItem. To do this, I've used the ListBox SelectionChange event:
private void CoverFlowList_SelectionChanged(object sender,
System.Windows.Controls.SelectionChangedEventArgs e)
{
MediaBox.Stop();
ListBoxItem SelectedItem = (ListBoxItem)sender;
ContentItem SelectedContent = (ContentItem)SelectedItem.Content;
MediaBox.Source = new Uri(SelectedContent.ResourceUrl);
MediaBox.Play();
}
But this does not want to work. When I debug the code, I can step all the way to ListBoxItem SelectedItem = (ListBoxItem)sender;
but at this line it all freezes. The webbrowser shows a blank page, and the debugger (Visual Studio 2008) seems is still debugging but nothing happens.
Any idea what I'm doing wrong here? Any tips on how I could implement this functionality different?
I'm very thankful for advice!
The error was in my typecasting. Changing
ListBoxItem SelectedItem = (ListBoxItem)sender;
ContentItem SelectedContent = (ContentItem)SelectedItem.Content;
into
ContentItem SelectedItem = (ContentItem)((ListBox)sender).SelectedItem;
Solved it. So the obvious error was that the ListBoxItem was not the sender since the ListBox ofcourse was the sender.
Thanks to everyone who wasted valuable time trying to correct my sloppy written code.
What I did:
Uri SomeVariable = new Uri("Devil May Cry - Shall Never Surrender", UriKind.RelativeOrAvsolute);
MyPlayer.Source = SomeVariable;

Resources