How to allow user to change property in a template? - silverlight

I have a button which in Blend I have edited (using Edit current template). I have added my animations for mouse over etc and the button works as expected.
However, on the mouse over event I have a shape that scales. What I want to do is give the user the option to set in XAML the rotation and scaling properties.
So for example, something like this:
<Button Height="76" Content="Gallery" Style="{StaticResource RotatingAnimationButton}" " Scaling="2.0" >
where in the template I have :
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="Document" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].
(ScaleTransform.ScaleX)">
where Value="1.5" would be changed to "2.0".
Currently, all I have is the style of the template. I am not sure whether I can pass in the parameters or I have to create some sort of user control?
JD
Note : This question was originally posted as Silverlight and WPF. But as you will see it only applies to Silverlight which is why the excellent solutions provided caused me problems.

You have two good options:
You can subclass Button and add a "Scaling" property, or
You can create an attached "Scaling" property and attach it to Button
In either case, your animation can bind to it.
Unless your button is custom in other ways, I would generally go with the attached property. You would use a standard attached property template (use the "propa" snippet):
public class MyAttachedProperties
{
// Scaling
public static double GetScaling(DependencyObject obj) { return (double)obj.GetValue(ScalingProperty); }
public static void SetScaling(DependencyObject obj, double value) { obj.SetValue(ScalingProperty, value); }
public static readonly DependencyProperty ScalingProperty = DependencyProperty.RegisterAttached("Scaling", typeof(double), typeof(MyAttachedProperties));
}
In the code that uses the button you would reference it like this:
<Button Height="76" Content="Gallery"
Style="{StaticResource RotatingAnimationButton}"
local:MyAttachedProperties.Scaling="2.0" />
In the template you would bind it like this:
Value="{Binding Path=(local:MyAttachedProperties.Scaling),
RelativeSource={RelativeSource TemplatedParent}}"
Both of these bits of XAML assume you have xmlns:local defined to include the MyAttachedProperties class.

Related

Set default text for textbox in WPF

I need all my textboxes to have a default text so I have done what is explained in this another post. I have used the solution proposed by Steve Greatrex and marked as accepted.
It is working for me but now I am trying to improve it to use in multiple textboxes as a template but for each of my textboxes I want to set a custom different default text.
As template default text is set to whatever, for example "Your Prompt Here" in above link, then all the textboxes I bind this template will have the same text.
I would like to put a different default text for each of my textboxes so how can I do it using the same controltemplate for all the textboxes?
Under "Windows.Resources" I have created an style that cotains the template indicated in the above post:
<Style x:Key="DefaultText" TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<!-- here the controltemplate from the above post -->
</Setter.Value>
</Setter>
</Style>
and I use it in my textboxes in the following way:
<TextBox Style="{StaticResource DefaultText}"/>
Use custom attached property instead of the Tag which has no any specific semantic:
public static class TextBoxHelper
{
public static readonly DependencyProperty DefaultTextProperty = DependencyProperty.RegisterAttached(
"DefaultText",
typeof(string),
typeof(TextBoxHelper));
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static string GetDefaultText(FrameworkElement element)
{
return (string)element.GetValue(DefaultTextProperty);
}
public static void SetDefaultText(FrameworkElement element, string value)
{
element.SetValue(DefaultTextProperty, value);
}
}
Then you can use it from XAML:
xmlns:helpers="<your_namespace_with_helpers>"
<TextBox helpers:TextBoxHelper.DefaultText="..."/>
Then in your ControlTemplate you can set Text like this:
Text="{Binding Path=(helpers:TextBoxHelper.DefaultText), RelativeSource={RelativeSource TemplatedParent}}"
Although this approach is more verbose than using the Tag property I recommend you to use it because:
If your code will be maintained by someone else it will be quiet unexpected for this person that control relies on Tag property which can contain anything since its type is object.
DefaultText attached property has strict semantic. Anyone can say what it needed for just looking on its name and type.
Rule of thumb is always try to avoid using of properties with undefined semantic.
I have solved it by replacing Text property in textblock within control template by this one:
Text="{TemplateBinding Tag}"
then I call it from any textbox like below:
<TextBox Style="{StaticResource WatermarkedTextBox}"
Tag="Type whatever here" />
You can choose default text for each textbox by specifying the Tag property.
Also, this solution does not require the aero theme.
The solution that Clemens propose in this link also works and it is based on aero theme.

How to build form at runtime in WPF MVVM based application

How to build form at runtime in WPF-MVVM (PRISM) based application.
Requirement is like user should be able to add control like textbox, checkbox, combobox etc. at runtime.
after adding the crontol user will save the form and all the configuration will get saved in database.
So that application can create the form at runtime based on the configuration stored in database.
How can we achieve this?
Thanks.
I've done something similar, although not with standard UI controls. I have a series of classes representing the "controls" I want to display - in my scenario these represent physical devices like pumps, valves, switches, displayed on a machinery "control panel" that the user can configure. These classes inherit from a base class (call it "HardwareItem") which exposes some properties that are common to all controls, e.g. Top, Left, Width, Height, Tooltip, etc.
The "designer"
The window where the user "designs" a form consists of the following components:-
A "toolbox", basically an ItemsControl bound to a VM List<HardwareItem> property that exposes the available HardwareItems (created and populated by the VM's constructor)
A canvas, that the user can drag items onto from the toolbox. When a drop happens, I instantiate the appropriate HardwareItem object and add it to a collection (used to keep track of what controls have been added). To render the control on the canvas, I create a ContentControl and set its "Source" property to the HardwareItem object, then add that to the canvas at the drop position. The control's visual is rendered using XAML DataTemplates that I've created for each HardwareItem type.
A PropertyGrid control (part of the free Xceed toolkit). When the user selects a control on the canvas, the corresponding HardwareItem object is wired up to the PropertyGrid, allowing the user set its property values (I use a custom attribute to control which properties should appear in the grid).
When the user clicks "save", I basically just serialize my collection of HardwareItem objects to a string using Json.Net then saved to file.
"Runtime"
To render a previously designed form, the file is deserialized back into a collection of HardwareItem objects, and added to a canvas in pretty much the same way as described above.
Doing something similar with standard WPF controls shouldn't be too dissimilar. You could create classes that expose just the properties that you want a user to manipulate, e.g.:-
// Base class
public class MyControl
{
public double Top {get;set;}
public double Left {get;set;}
public double Width {get;set;}
public double Height {get;set;}
}
// TextBox
public class MyTextBox : MyControl
{
public string Text {get;set;}
}
// Button
public class MyButton : MyControl
{
public string Caption {get;set;}
public ICommand ClickCommand {get;set;}
}
The DataTemplates might look something like this:-
<DataTemplate DataType="{x:Type MyTextBox}">
<TextBox Text="{Binding Text}"
Width={Binding Width}" />
</DataTemplate>
<DataTemplate DataType="{x:Type MyButton}">
<TextBox Content="{Binding Caption}"
Width={Binding Width}"
Height={Binding Height}"
Command={Binding ClickCommand} />
</DataTemplate>
Much of the canvas manipulation is done in code-behind rather than the VM. It's "UI logic" so is a perfectly acceptable approach.
Prism is not used at all here (I use it for navigating between views, but it doesn't play a part in this "form designer" functionality).

WPF MVVM - How to Bind Custom Control->ToggleButton.IsChecked to View->TextBox.Text

I am moving over from WinForms to WPF and trying to implement the MVVM pattern for a touchscreen application. I created several custom controls inside a WPF Control Library (dll), and I can bring these controls into the View with no issue. However, I am getting stuck on a purely academic scenario where I want a TextBox inside the View to display my custom control's ToggleButton.IsChecked property as "Checked" and "Unchecked" respectively.
To sum up, I need to know the proper way to expose properties of a control that is inside a custom user control. Then when the exposed property changes update some other control with custom data based on the property that changed.
To sum up, I need to know the proper way to expose properties of a control that is inside a custom user control. Then when the exposed property changes update some other control with custom data based on the property that changed.
You're describing dependency properties. You need to add a dependency property to your custom control, which you then bind to from inside the control, and from outside it (in your view).
The first part will depend on whether you're using a UserControl or a Control. Let's say it is a Control, then you would use a TemplatedParent binding in your ControlTemplate:
<ToggleButton IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent},Path=IsToggleChecked,Mode=TwoWay}" ... />
If on the other hand it is a UserControl, then the approach is similar, but you need to make sure the data context is right. One approach would be to use a FindAncestor binding:
<ToggleButton IsChecked="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=IsToggleChecked,Mode=TwoWay}" ... />
Now, to add the dependency property, try the Visual Studio code snippet "propdp". It should look something like this:
public bool IsToggleChecked
{
get { return (bool)GetValue(IsToggleCheckedProperty); }
set { SetValue(IsToggleCheckedProperty, value); }
}
public static readonly DependencyProperty IsToggleCheckedProperty =
DependencyProperty.Register("IsToggleChecked", typeof(bool), typeof(MyCustomControl), new PropertyMetadata(false));
And now finally you can bind your TextBox to the new dependency property:
<TextBox Text="{Binding ElementName=myCustomControl,Path=IsToggleChecked,Converter={StaticResource BoolToTextConverter}}" />
<local:MyCustomControl x:Name="myCustomControl" ... />
I assumed that you would want to make an IValueConverter "BoolToTextConverter" that converts the boolean value to the string "Checked" or "Unchecked".

Enable button based on TextBox value (WPF)

This is MVVM application. There is a window and related view model class.
There is TextBox, Button and ListBox on form. Button is bound to DelegateCommand that has CanExecute function. Idea is that user enters some data in text box, presses button and data is appended to list box.
I would like to enable command (and button) when user enters correct data in TextBox. Things work like this now:
CanExecute() method contains code that checks if data in property bound to text box is correct.
Text box is bound to property in view model
UpdateSourceTrigger is set to PropertyChanged and property in view model is updated after each key user presses.
Problem is that CanExecute() does not fire when user enters data in text box. It doesn't fire even when text box lose focus.
How could I make this work?
Edit:
Re Yanko's comment:
Delegate command is implemented in MVVM toolkit template and when you create new MVVM project, there is Delegate command in solution. As much as I saw in Prism videos this should be the same class (or at least very similar).
Here is XAML snippet:
...
<UserControl.Resources>
<views:CommandReference x:Key="AddObjectCommandReference"
Command="{Binding AddObjectCommand}" />
</UserControl.Resources>
...
<TextBox Text="{Binding ObjectName, UpdateSourceTrigger=PropertyChanged}"> </TextBox>
<Button Command="{StaticResource AddObjectCommandReference}">Add</Button>
...
View model:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
OnPropertyChanged("ObjectName");
}
}
// Command bound to button
public ICommand AddObjectCommand
{
get
{
if (addObjectCommand == null)
{
addObjectCommand = new DelegateCommand(AddObject, CanAddObject);
}
return addObjectCommand;
}
}
private void AddObject()
{
if (ObjectName == null || ObjectName.Length == 0)
return;
objectNames.AddSourceFile(ObjectName);
OnPropertyChanged("ObjectNames"); // refresh listbox
}
private bool CanAddObject()
{
return ObjectName != null && ObjectName.Length > 0;
}
As I wrote in the first part of question, following things work:
property setter for ObjectName is triggered on every keypress in textbox
if I put return true; in CanAddObject(), command is active (button to)
It looks to me that binding is correct.
Thing that I don't know is how to make CanExecute() fire in setter of ObjectName property from above code.
Re Ben's and Abe's answers:
CanExecuteChanged() is event handler and compiler complains:
The event
'System.Windows.Input.ICommand.CanExecuteChanged'
can only appear on the left hand side
of += or -=
there are only two more members of ICommand: Execute() and CanExecute()
Do you have some example that shows how can I make command call CanExecute().
I found command manager helper class in DelegateCommand.cs and I'll look into it, maybe there is some mechanism that could help.
Anyway, idea that in order to activate command based on user input, one needs to "nudge" command object in property setter code looks clumsy. It will introduce dependencies and one of big points of MVVM is reducing them.
Edit 2:
I tried to activate CanExecute by calling addObjectCommand.RaiseCanExecuteChanged() to ObjectName property setter from above code. This does not help either. CanExecute() is fired few times when form is initialized, but after that it never gets executed again. This is the code:
// Property bound to textbox
public string ObjectName
{
get { return objectName; }
set {
objectName = value;
addObjectCommand.RaiseCanExecuteChanged();
OnPropertyChanged("ObjectName");
}
}
Edit 3: Solution
As Yanko Yankov and JerKimball wrote, problem is static resource. When I changed button binding like Yanko suggested:
<Button Command="{Binding AddObjectCommand}">Add</Button>
things started to work immediately. I don't even need RaiseCanExecuteChanged(). Now CanExecute fires automatically.
Why did I use static resource in first place?
Original code was from WPF MVVM toolkit manual. Example in that manual defines commands as static resource and then binds it to menu item. Difference is that instead of string property in my example, MVVM manual works with ObservableCollection.
Edit 4: Final explanation
I finally got it. All I needed to do was to read comment in CommandReference class. It says:
/// <summary>
/// This class facilitates associating a key binding in XAML markup to a command
/// defined in a View Model by exposing a Command dependency property.
/// The class derives from Freezable to work around a limitation in WPF when
/// databinding from XAML.
/// </summary>
So, CommandReference is used for KeyBinding, it is not for binding in visual elements. In above code, command references defined in resources would work for KeyBinding, which I don't have on this user control.
Of course, sample code that came with WPF MVVM toolkit were correct, but I misread it and used CommandReference in visual elements binding.
This WPF MVVM really is tricky sometimes.
Things look much clearer now with the edits, thanks! This might be a stupid question (I'm somewhat tired of a long day's work), but why don't you bind to the command directly, instead of through a static resource?
<Button Command="{Binding AddObjectCommand}">Add</Button>
Since you are using the DelegateCommand, you can call it's RaiseCanExecuteChanged method when your text property changes. I'm not sure what you are trying to accomplish with your CommandReference resource, but typically you just bind the commands directly to the button element's Command property:
<TextBox Text="{Binding ObjectName, UpdateSourceTrigger=ValueChanged}" />
<Button Command="{Binding AddObjectCommand}" Content="Add" />
This would be the relevant portion of your view model:
public string ObjectName
{
get { return objectName; }
set
{
if (value == objectName) return;
value = objectName;
AddObjectCommand.RaiseCanExecuteChanged();
OnPropertyChanged("ObjectName");
}
}
Try raising CanExecuteChanged when your property changes. The command binding is really distinct from the property binding and buttons bound to commands are alerted to a change in status by the CanExecuteChanged event.
In your case, you could fire a check when you do the PropertyChanged on the bound property that would evaluate it and set the command's internal CanExecute flag and then raise CanExecuteChanged. More of a "push" into the ICommand object than a "pull".
Echoing Abe here, but the "right" path to take here is using:
public void RaiseCanExecuteChanged();
exposed on DelegateCommand. As far as dependencies go, I don't think you're really doing anything "bad" by raising this when the property that the command depends on changes within the ViewModel. In that case, the coupling is more or less contained wholly within the ViewModel.
So, taking your above example, in your setter for "ObjectName", you would call RaiseCanExecuteChanged on the command "AddObjectCommand".
I know this is an old question but I personally think it's easier to bind the textbox Length to button's IsEnabled property, e.g.:
<TextBox Name="txtbox" Width="100" Height="30"/>
<Button Content="SomeButton " Width="100" Height="30"
IsEnabled="{Binding ElementName=txtbox, Path=Text.Length, Mode=OneWay}"></Button>
If ElementName binding does not work, use:
<Entry x:Name="Number1" Text="{Binding Number1Text}" Keyboard="Numeric"></Entry>
<Entry x:Name="Number2" Text="{Binding Number2Text}" Keyboard="Numeric"></Entry>
<Button Text="Calculate" x:Name="btnCalculate" Command="{Binding CalculateCommand}" IsEnabled="{Binding Source={x:Reference Number1, Number2}, Path=Text.Length, Mode=OneWay}"></Button>
or use:
<Entry x:Name="Number1" Text="{Binding Number1Text}" Placeholder="Number 1" Keyboard="Numeric"></Entry>
<Entry x:Name="Number2" Text="{Binding Number2Text}" Placeholder="Number 2" Keyboard="Numeric"></Entry>
<Button VerticalOptions="Center" Text="Calculate" x:Name="btnCalculate" Command="{Binding CalculateCommand}">
<Button.Triggers>
<DataTrigger TargetType="Button"
Binding="{Binding Source={x:Reference Number1, Number2},
Path=Text.Length}"
Value="{x:Null}">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Button.Triggers>

How to connect a Button in a Silverlight ListItem DataTemplate, in a ResourceDictionary (Styles.xaml), with a handler?

OK, so the situation is I'm defining an ItemTemplate for a ListBox in a ResourceDictionary (Styles.xaml). The ListBoxItem Template looks something like this:
<ControlTemplate TargetType="ListBoxItem">
<Button Command="{Binding Path=DoSomeCommand}" Content="Test" />
</ControlTemplate>
Now wherever this template is used, I'd like to have this button's click bind to an available ViewModel command to handle it.
However this does not work as is, I've also tried this:
<ControlTemplate TargetType="ListBoxItem">
<Button Command="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DoSomeCommand}" Content="Test" />
</ControlTemplate>
But still no dice.
A simple example that does work is if you define the template in the control (resources) that is using it, and just use an event handler (the same handler for all generated XAML.
Any ideas or thoughts on the best way to accomplish this? I figure this must be a common scenario: the goal is just to allow the user to interact with the items in the ListBox.
Thanks!
OK I think I answered my own question :
The solution seems to be to use 'nested' ViewModels here:
In other words, rather than have my ListBox bind directly to a collection of DTOs/business objects (as I was doing above) I instead created a simple ViewModel to wrap each DTO, and have the command on it, rather than on the original, top-level VM.
So the bound collection now looks like this:
TestItems = new ObservableCollection<ItemVM> ()
{
new ItemVM(),
new ItemVM(),
new ItemVM()
};
And each ItemVM just wraps the DTO, and has the command:
public class ItemVM : INotifyPropertyChanged
{
public ItemVM ()
{
this.MyCommand = new DelegateCommand<string> ( TheCommand );
}
public ICommand MyCommand { get; private set; }
public MyBusinessObject BizObj;
}
And voila, no need for a RelativeSource, and we have a reusable template complete with commands.
Long answer: Reference to a TextBox inside a DataTemplate
Short answer: Use Prism Commands or Blend Behaviours.

Resources