I'm looking for a SL4 equivalent to .NET 4's SetCurrentValue API, which would appear to be exactly what I need for my scenario.
In short, I'm writing an attached behavior that updates the value of a given property at appropriate times. However, I don't want it to overwrite any bindings that are set on that dependency property. I merely want to push that value to the property (and therefore have any bindings refresh based on that value).
From what I can tell, there's no easy way to do this yet in SL4.
Thanks
Silverlight does not provide direct access to this level of dependency value. However its this level of value that Animations in storyboards set when they manipulate a property.
Hence a Storyboard with a 0 length duration containing a single DiscreteObjectKeyFrame might achieve your desired result.
I've managed to simulate what I'm after by detecting bindings and injecting a surrogate object between the source and target. I can then manipulate the surrogate and have both sides of the original binding refresh.
It's ugly and more work than I'd like, but it seems to work.
Kent
Related
DependencyObjects can have SetValue() available and most (if not all) of WPF's stock UIElement derived controls contain DependencyObject properties than can be set via SetValue. Sometimes it is practical to do code-behind in a WPF application. Below produces similar result. But which one is better?
<TextBlock x:Name="myTextBlock" Loaded="myTextBlock_Loaded"/>
And setting the Text property can be done in two ways.
myTextBlock.Text = "foo";
OR
myTextBlock.SetValue(TextBlock.TextProperty, "foo");
Maybe the difference is trivial but I'm curious whether there is an advantage of using the one over the other.
There is a slight performance boost* in the second, as the implementation of TextBlock.Text set is actually return this.SetValue(TextBlock.TextProperty, value);.
However it should be noted that it is possible to get the second implementation wrong, for example you could end up typing
myTextBlock.SetValue(Grid.ColumnProperty, "foo");
Which would compile, but likely not run (or at least not give the expected result).
Further, the former will give you type-safety that the later would not give.
*"This performance boost" should however be JITed away.
Dependency properties with actual properties are essentially conveniences to get or set those properties through code. All dependency properties for all dependency objects are backed by a "dictionary" of key/values. Those values are accessed through the GetValue() and SetValue() methods.
What is "better" all depends on how you intend to use the properties. All builtin controls define properties to make it easier to initialize the objects through code. It would be far messier if you tried the same using the Get/Set methods.
But don't look at it in terms of what is "better," you'll get nowhere thinking in that way. Both are necessary. The dependency properties are how you get/set observable properties of dependency objects. Making those properties accessible with corresponding properties makes using your code easier.
If you don't need to access these dependency properties through code, then I suppose you could argue that the properties are not needed, but then nobody would want to use it.
I've stuck with one pretty trivial problem (at first look).
Simplified version of my situation looks like this:
I want multiple Background(for example) colors to be applied to SAME Control and to be able to clear only some of them (by condition). WPF does not offer such capability, I can set only one value for each DP.
So, I want to apply Yellow then Green then Red colors successively to Control object and then be able to reset Red so that Control will be with Green background (on the other hand, reseting Green leaves background Red). Looks pretty simple, have you ever created such Decorator for Control? I believe DP internally use such behavior, but there are no public APIs for it.
Please, do not suggest using triggers or any other kinds of conditional DP setting, I really need to set multiple values for single DP and to be able to manage them
Its not a good idea to say "do not suggest" ... Anyway, Well its not possible, and WPF does not do this, what you might meant is the value precendence but this List is fixed, you can't just add another layer in between, for good reasons. The whole system relys on that. Otherwise you could not set one value and use triggers to override it and don't need to take care of resetting the value. Also animations, Style inheritence etc. wouldn't be possible if people start to mess with this list.
So you don't like the trigger idea ... Why? Its exactly for that.
Ok, if you don't like it, how about adding an attached property for Background1, Background2 etc. You also could make Background as an attached property and make it inheritable. You could make an attached behavior, listen to property changes and modify your Background color. You could use a MultiBinding or PriorityBinding.
Well alot of stuff is possible if the obvious solution is not desired :)
Someone suggested in another question that they, at some point, were able to bind a value to a field in WPF.
I know that this is not a supported scenario (and personally I have only seen binding work with properties), but is it even technically possible?
No. Binding in WPF uses either a PropertyDescriptor or the Dependency Property mechanism, which only works on Properties.
(Technical note here: A Dependency Property is technically sort of a field - it's defined as a field, then registered with the DP system, though, and treated more like a property, so I would still call it a property... The field itself doesn't actually store the data in the case of a DP.)
If I had a label on a view that I wanted to have the width equal to the width of two columns in one of my grids on the same view, how would I set up the binding without using a converter? Should I use properties to preform my calculation and store a value? It is my intention that if the view's grid size changes then this label's size will also change to match the new width of the two columns.
And where should I put this logic? I am trying to follow MVVM pattern but I see that a lot of threads about "converters in MVVM" say to put the logic into the viewmodel.
I tried to implement this behavior with dependency properties on my view since my viewmodel technically has no knowledge of my view (so how would my viewmodel know how wide my columns currently are?). This goes against what I have read online though. When implementing this behavior I noticed that I cannot reference my columns by name unless my property is not static, but dependency properties are static so I am not sure how to shuffle my values around without creating yet more properties to hold values.
Can someone provide help here? I feel like i'm overcomplicating this. I just need this label to sit over these two columns however they stretch. It just provides a visual grouping of related fields in the grid. Once I can do this first one, the other two should be equally similar.
My rule of thumb is if it's "View" related then keep it away from the ViewModel. From your description this sounds like it's purely view related, so I would just use logic in either the codebehind or a converter.
Now what I don't understand is why you are reluctant to use Converters. With converters you certainly don't want to store business logic that is going to lead to confusion or pain points for refactoring, but if you have some value that needs to be converted for a specific view operation then Converters are exactly what you should be using.
So my advice is Converters ... if it's View related then feel free to use Converters and Codebehind ... in fact you should use them and not the ViewModel.
Does that help?
We are using the standard method for our controls to report broken BO rules. This is done via the interface IDataError in our BO’s and in XAML the control is bound to the BO’s property etc. This approach works OK. But we need to show 2 types of visuals in the UI depending on the type (or category if you like) of the invalidation error. If it’s a required field then we show a CueBanner (water mark) but for other types we change the colour of the controls boarder. In both scenarios we set the tool type of the error message.
The Problem with IDataError is that it doesn’t support a method/property to distinguish between error types.
The only way I can do that is by examining the error text, required field text must contain the key word “required”. The following approach doesn’t feel right but it’s the only way I can determine the type of error and then deal with it accordingly. All required field rules must have as part of the error text “required field”.
To make this all work I have created a custom dependency property called ErrorMessage. In my ResourceDictionary I have a Style.Trigger for Validation.HasError. In there I set my dependency properties value to the ErrorContent. Now when my dependency properties value changes I can examine the text and set the Validation.SetErrorTemplate( myControl, newErrorTemplate) to the template to suit the error type. I have to wire up a few events to the control such as lost and got focus to manage removing or adding the cueBanner template but the whole thing will work. It’s just that I’m not sure it’s the best way to do it.
PS. When I set the ErrorTemplate i’m doing this in code, thats building and adding it. Is there a way to point Validation.SetErrorTemplate to a static resource keeping in mind that I need to switch between at least 2 types?
Your thoughts please..
Would it be possible to derive an interface IDataError that adds an extra property which is an enumeration of the error type. Then you could try and bind against it.
If you're okay with an (untested)approach that suffers a little bit of clarity, then you could do the following:
throw an exception instead of returning an string with the IDataErrorInfo Interface. In your ErrorTemplate, you can access the ValidationErrors (and the ValidationError.Exception Property).
Then, you use a DataTrigger on the Exception in combination with a converter, that checks for the right Exception-Type and return true or false. It should be enough to do the job.