I need to extend a button control to add some additional, bindable, visual states.
What I would like to create is an additional boolean property, to bind to, that will create a simple visual state change on the button. For this example, it could just be an additional border which changes colour according to the boolean value.
All the existing button behaviour should be entirely seperate from this new set of states.
Can this be done?
This can certainly be done. Here's a post that walks you through the steps you'll need to take, and includes additional information for extending the control with properties (besides just those to hold state) that show up in the final control. The pieces you'll need are:
A class that derives from Button (your custom control class)
A default style for this control (which goes in /themes/generic.xaml). You can start off with Button's generic style and add your states to it.
A dependency property that holds your boolean value
A new VisualStateGroup that holds your two new states
Some code in your class that glues together changing states with the boolean value you've defined, presumably resulting from user interaction, etc.
You may find it's easier to edit the visual state in Blend, depending on how sophisticated your transitions will be, etc.
Related
I have a DataTemplate(well two data templates) that I want to use as views for some
basic form viewmodels(that that contain a value and and boolean indicating whether I want to use the value).
I want to use the datatemplate(s) several times for separate form items. I think the right way to do this is to set it as the ContentControl's ContentTemplate (in that case it will have the same data context right?) but I also want to pass the label string and since the label string is part of the ui and doesn't change it seems wrong to put it in the viewmodel object. How do I give access of the label string to the DataTemplate instance?
Just like its name, a DataTemplate is used to template the Data... For example, if you have a class called MyItem which has a Name and Value and you want this shown in a specific way, you'll set a datatemplate for Item and use it whenever needed.
In your case, you're speaking about having very similar views, with only a minor change between them. This minor change (if I understood your question correctly) is not something that comes from the model or from the viewmodel but something which is entirely view-oriented (a different title for the page, for instance).
If you plan on using a different viewmodel for every view, and each viewmodel has a different purpose - I don't see a problem with adding a Title property to the VM and bind to that too (Remember, MVVM is a set of guidelines, not rules...)
If you still rather have it separated from the viewmodel, then you can use an Attached Property. Create an Attached Property called TemplateTitle, for instance, and have each contentcontrol in each view change it. The label, of course, will bind to that Attached Property.
I have a form in my WPF application that I have to add an Edit button to. Right now, the form is always in edit mode and there is no "view mode". However, for various reasons, I need to keep the control in view mode until the user clicks an Edit button, and then hide the edit button and display a Save button in its place.
My form already has a bool DependencyProperty called CanModify, which is true when the user's permissions give them the right to edit the record being displayed in the form. I am adding a new bool DependencyProperty called InEditMode, which will default to false. Hiding and enabling the buttons is pretty straight forward, but I have this ComboBox control that I want to hide if the user can't edit the record, or if they can edit it and the form is in view mode. For that, I need to convert the result of ANDing the two bool properties together and then convert it into a Visibility value.
I've already got a class that implements IValueConverter and converts a bool into a Visibility. I've just written a class that implements IMultiConverter which takes an array of bools and ANDS them together (or ORs them, depending on the value of the parameter).
What I'd like to do is to take the result of the IMultiConverter and put it through the IValueConverter to convert the result into a Visibility. Can I do that? Or would I be better off doing the AND in the code behind to a new DependencyProperty?
Tony
You can indeed chain converters, my own example does not yet deal with MultiValueConverters but it shouldn't be too hard to implement a LinkedMultiValueConverter. One of the downsides of this approach is that you would have to recreate any converters you currently have to use the provided attribute.
git://github.com/pmacn/ValueConverters.WP8.git
or
https://github.com/pmacn/ValueConverters.WP8
and then you would do the following
<con:LinkedConverter x:Name="MyFancyLinkedConverter">
<con:BooleanInversionConverter />
<con:BooleanToVisibilityConverter />
</con:LinkedConverter>
You can't chain converters.
Instead change your MultiValueConverter to take a string parameter, "bool" or "visibility". Depending on the parameter return either a bool or visibility object
Because you can't chain converters, I added another boolean property to my class. I added methods to the two properties the new one is dependent upon that are called when they change. These recompute the value of the new property. I then used my original boolean to visbility converter to show or hide the control in question.
I’m trying to extend an Expander’s header (the ToggleButton part) to allow for some more custom features. Being rather new to extending WPF controls using ControlTemplates, I have already accepted by now, that I will have to completely replace the Expander’s template by my own (without being able to reuse originally defined components, or even styles, which makes this quite a bit annoying in my opinion – but that’s not what the question is about).
However, I wanted to introduce some properties which change the way the component looks and works. So I created a new subtype of Expander which simply defines the new dependency properties I want to use. But I noticed that, given that I want to use those properties within the template for the ToggleButton, which is nested inside of the one for the Expander, I cannot use those properties like that. So I had to subtype ToggleButton too, define the dependency properties for that type as well, and make the Expander’s template pass the values through to the ToggleButton template.
So I ended up with two new types in the namespace (nesting the new ToggleButton type inside of the Expander subtype didn’t work?), a complete copy of the Expander’s template with only a single line changed (where the ToggleButton was inserted, passing through the new properties), and then the actual desired changes for the ToggleButton template.
And here comes the question: Is there any way to make this less complicated? To reduce the amount of work that needs to be done just for extending a subcomponent of another’s template? Or just a way to use the parent’s (Expander) properties inside of the ToggleButton template without having to subtype that one as well?
I ended up using what jberger suggested in the comments:
Using the following binding expression I did not need to duplicate the DependencyProperties into another component for the ToggleButton, but could just access the Expander’s properties inside the nested template:
{Binding CustomProperty, RelativeSource={RelativeSource
FindAncestor, AncestorType=local:CustomExpander}}
Sadly, but as expected, one apparently cannot reuse template parts from the default. However in this case I could leave out parts from the original template that I didn’t need in my copy. For example the different styles for non-default expanding (i.e. other than Top), as my expander is specialized to that layout.
This however rendered the ExpandDirection property useless, but I personally can accept that. It might lead to a follow-up question though; if one should rather build the component from scratch (based on Expander’s base, instead of Expander itself).
I am having a number of controls in my application(which user can add to canvas), each having various properties(mostly dependency properties). User can change its properties through property grid(like color, text etc.).
I have save functionality implemented, so if user makes any change in canvas we ask him to save the document before leaving. At present I am keeping track of Add/Delete/Resize like operations(changing IsChanged flag to true). I also want to keep track of any property changes done by user, say if he changes the color of control through propertygrid.
One straightforward solution is to handle PropertyChangedCallback for each proeprty and set the flag in that. Problem with this is that I will have to write PropertyChangedCallback for each proeprty in each control, and at the same time I will have to make sure that every new proeprty added do the same.
My question: Is there any other better way of tracking property changes, say at some global place?
If your objects/classes are DependencyObjects, you could create your own 'base class', deriving from DependencyObject which overrides OnPropertyChanged:
http://msdn.microsoft.com/en-us/library/system.windows.dependencyobject.onpropertychanged.aspx
In the implementation you could register that the object had changed in some singleton or associated change-tracking manager class, then call base.OnPropertyChanged.
Then change all your objects to implement this new class rather than DependencyObject and when any properties change your code will get called.
Hope that helps!
I have a user control which datacontext is set to a view model. The user control contains some textblocks and textboxes which are bind to view model's properties. I would like to do a small animation when a view model's property's value changes but I can't seem to find a way to do this in Silverlight.
In WPF we can use properties like NotifyOnTargetUpdated and Binding.TargetUpdated to capture the change but they seem to be missing from Silverlight. In my case the animation isn't based on the property's value, meaning I don't want to start the animation when some property's value is for example 5. Instead the animation should start every time the property's value is changed (to highlight the changed content for the user).
Here's the answer on how to do this in WPF: Animate WPF Text when binding updates, how?
But how can I do the same with Silverlight 4?
you should be able to get this done using the new trigger stuff included in Expression Blend 4. There's a whole bunch of ne behaviors/triggers etc. that let you react to changes in the ViewModel, for instance.
From the Expression Blend feature page:
New Behaviors
Expression Blend includes the new TranslateZoomRotateBehavior multi-touch Behavior, and a PanningItems control that you can use to scroll between items by using touch. Expression Blend also has a new trigger that responds to a frame change or the pausing or completion of a SketchFlow animation, called the SketchFlowAnimationTrigger. Expression Blend has new sets of Behaviors for dragging items between list boxes, for modifying menu navigation, and for preserving screen states, such as SetDataStoreValueAction and DataStoreChangedTrigger.
An exciting enhancement has been made to the FluidMoveBehavior: if you apply it to different views of the same data item, when the item moves from one view to another (for example, from a list view to a details view), it fluidly animates the transition between the two views.
New Behaviors for use with applications that use the Model-View-ViewModel pattern include the following: CallMethodAction, InvokeCommandAction, and DataStateBehavior. You can use these Behaviors to invoke behavior on your ViewModels, or to respond to changes to their properties.
Conditional Behaviors and the data store
You can now build conditional logic into your prototypes and production applications without the need to write code. In fact any action can be associated with a set of conditions that must be met in order to execute the action. The new data store feature enables application variables, such as the current user's role, for example, can be read from and written to so that, effectively, different parts of your application can communicate via this shared state.
New behavior components introduced as part of this feature include the conditions editor that appears in the Properties panel for every action, a SetDataStoreValueAction action that allows you to manipulate values in your data store, and a DataStoreChangedTrigger trigger that fires whenever a chosen property inside the data store is changed.
http://www.microsoft.com/expression/products/Blend_Features.aspx
Cheers, Alex