In a drawing application that allows user to add different objects like Rectangle, Ellipse, Text, Image etc, I have a "color box" that lets user see or change the fill of selected object(s). If there are multiple objects selected, I can't obviously show all, so I show the color of first selected object. When user changes the color of "color box", I want to change the fill of all selected objects. (That's also how VS properties window works btw)
How do I bind my "color box"'s Brush property (type Brush) to do this thing?
What I have already tried is this: I bind "color box"'s Brush property to selection object and then use a Converter that examines the selection object and if there is one or more objects in it, it returns the color of first selected object in Convert() function.
Problem however is that I have no way of implementing ConvertBack(), because it doesn't give me access to the selection object, so that I could iterate through the selected objects and assign them newly selected color.
Using MultiBinding is also of no use, as value parameter of ConvertBack() is a single object and doesn't give me access to the selection object. One idea was to supply selection object using ConverterParameter, but ConverterParameter is not bindable.
Another idea (hack?) was to keep a class level variable to point to selection object and assign in Convert() function (by passing selection object in MultiBinding) and then use that variable in ConvertBack(), but I don't know how safe it is and whether Convert() and ConvertBack() will always be called in order.
So how do I achieve this?
OK. This turned out to be easier than I thought. For future readers, I simply added a property to my VM of Brush type (call it SelectionBrush) whose getter would return the Brush of first selected object, and whose setter would iterate through the entire selection and assign the Brush to appropriate objects (by checking their types). No more converters needed!
Related
I have a WPFToolkit DataGrid with at least one column bound (via a proxy object as columns are not part of the visual tree) to a property. I wish to toggle all columns to Visible so that I can perform a calculation based on the DataGridColumnHeader (which is only created when its column is visible for the first time). Having done the calculation I want to reset the column to use the binding that was previously set.
I've attempted to get and store the Binding Expression etc, but with no joy. I have also attempted to use the DependencyObject.SetValue() method to change the property value non-destructively, but this doesn't event correctly change the value, let alone retain the original binding.
Any ideas?
You need to call SetCurrentValue() so that it won't clear the binding. SetValue destroys the old binding.
From MSDN:
This method is used by a component that programmatically sets the value of one of its own properties without disabling an application's declared use of the property. The SetCurrentValue method changes the effective value of the property, but existing triggers, data bindings, and styles will continue to work.
Given you have this
<TextBox Text="{Binding TestProperty}"/>
The SetValue you will overwrite the binding with whatever you provide. If you call SetCurrentValue, however, will ensure that the property takes on the given value, but won't destroy any bindings.
Be aware that you should not use SetCurrentValue in your dependency properties' setter/getter.
SetCurrentValue is more useful in scenarios where you need a property to take on a given value but don't want to overwrite any bindings, triggers, or styles that have been configured against your property.
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 am facing a small problem using silver light . I have a RadGridView, with four columns. My second columns contains text boxes and the third column contains validation errors. If the third column contains validation errors, i want the second column background to turn red. How can i do this. I have tried binding the text box background column to a string with the desired color but that does not work. Really stuck here. Any help with be much appreciated.
Regards,
Mateen
Assuming your binding is otherwise valid, you cannot change colour by binding to a text string of a colour. The background property is of type Brush.
You need to either bind to a Brush instead, or use a brush/colour converter to return a Brush instead of a Color/string etc.
Try these links for converter examples:
http://forums.silverlight.net/p/20392/70263.aspx
http://forums.silverlight.net/p/20392/70263.aspx
You need a StringToObjectConverter found here. This class has the advantage that it has wider uses that eliminate the need to create a plethora of similar converters.
Further rather than having the bound object have a property called "Background" which tell the UI to "be red". I would be better that the Model had a property called "Status" which is an enum of the possible states the object is in.
Going further and looking at your specific requirement it would be better that your model exposed a boolean IsValid property which a converter could be applied to. See this blog on a generic BoolToValueConverter.
I have a childwindow with a number of Textboxes, Comboboxes, and DatePickers. I want to know if a user has changed any value in these (to know if I need to save to db)
One way I could think of doing this are in the 'on chg' event handlers and set bool. But if a user changes the value, in say a combobox, then changes back to the original this would still be seen as a change.
Are there other alternatives?
(note the project is not set up as MVVM)
If you don't use mvvm but still bind to an object then:
before the window is shown create a copy of the object, save it, and bind it to DataContext
whenever you need to know if user made any changes you can compare the saved object to DataContext (property by property)
I you don't use binding at all then:
before the window is shown save all fields that can be modified to a Dictionary
whenever you need to know if user made any changes you can compare the dictionary values to values of the fields