This thread looks to be a little on the old side and therefore may no longer be relevant. Please see if there is a newer thread on the subject and ensure you're using the most recent build of any software if your question regards a particular product.
This thread has been locked and is no longer accepting new posts, if you have a question regarding this topic please email us at support@mindscape.co.nz
|
From a property in the WPFPropertyGrid, I simply want to call my custom window for a "select from list" option on a property. For example my property is City, a simple string. I want to offer the user a custom dialog that lists cities and returns the value. So I would like a "..." button at the right of the textbox that triggers calls the method that calls my popup. Is there some built-in editor support for this or suggestions? Preferrably an example of sending the current string and how to return and display the selected value. |
|
|
There's no built-in support for dialogs; we did think about this but the range of possible dialog interfaces (particularly considering common dialogs) put us off. So here's an example. You might also want to post in the thread at http://www.mindscape.co.nz/forums/Thread.aspx?ThreadID=1202 -- Mitch has been doing something similar and might be willing to discuss or share his solution. Anyway, the example. I'm going to use a quick and slightly dirty method for this; it could be cleaned up but hopefully it will give you the idea. First, the editor template. (I've made the text display read-only but you could easily use a TextBox instead of a TextBlock if you wanted users to be allowed to edit in place instead of using the dialog.) <DataTemplate x:Key="MyEditor"> We're using the Tag property of the Button as a data-bindable property that will be easy to get hold of from the event handler. This is the quick and dirty bit because Tag doesn't have any nicely reserved meaning, but it's safe unless some other piece of your code also uses Tag for something else. Cleaner options include defining a custom attached property but that would be a bit verbose for this sample. Don't forget to set the binding to be TwoWay so that changes to the Tag propagate back to the business object; this will cause the new value to be displayed automatically. Now for the Click handler. This will depend on how you want to create and exchange data with your dialog, e.g. constructor, settable property, DataContext, etc. For this sample I'm going to assume that the dialog has a SelectedItem property which you set or get to exchange data with the dialog. I've separated out the common logic of marshalling data into and out of the Tag property from the specifics of my sample dialog's interface so as to make it easier to replace the bits that are specific to your application. private void DlgButton_Click(object sender, RoutedEventArgs e) Incidentally, if you have several editors that all have the "text plus ellipse button" UI and behaviour, but need to pop up different dialogs, the latest nightlies include a feature which makes it easier to parameterise editors. So if you can define a standard interface for your dialogs (or even just for your GetDialogResult functions) then you only need to write the above editor and code once, and you can reuse it with different dialogs. I'll maybe post a sample on the blog about this if it's of interest. Let me know if you need any more information or clarification. |
|
|
Thanks for that. What I need is the property value and name to return a selected value. Binding to the Property(<Binding Property/>) provides the property details, but only read-only access to the value. I have over a hundred such properties that require sophisticated lookup assistance. My interrim solution is to bind the property to the parent panel and the value to the button: <DataTemplate x:Key='EditorWithLookup'><DockPanel> <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" Tag="{Binding Property}"> <Button x:Name="uxPropertyLookup" Content="..." Click="uxPropertyLookup_Click" Tag="{Binding Value, Mode=TwoWay}"/> <Button x:Name="uxPropertyGoto" Content="Edit" Tag="{Binding Property}"/> </StackPanel> <TextBox BorderThickness='0' Text='{Binding Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}'/> </DockPanel> </DataTemplate> And then retrieve both in the action and call a generic lookup with the property name: private void uxPropertyLookup_Click(object sender, RoutedEventArgs e){ FrameworkElement theButton = (FrameworkElement)sender; FrameworkElement thePanel = (FrameworkElement)theButton.Parent; Mindscape.WpfPropertyGrid.PropertyNode theNode = (Mindscape.WpfPropertyGrid.PropertyNode)thePanel.Tag; theButton.Tag = GetValueForProperty(theNode.Name); } Not pretty but gives me a single editor and method that I can change in the future. I'll keep a lookout in future releases to see if this can be done differently. |
|
|
May I offer a small suggestion for tidying this? Define a couple of attached properties, and set them on the uxPropertyLookup button. That way you don't need to rely on navigating the visual hierarchy to get bindings for both the Property and the Value. For example, you could declare attached properties as follows: public static class UXPropertyLookup (You could of course make the Value property more strongly typed if appropriate.) In your template, assign them on your button like this: <Button local:UXPropertyLookup.Value="{Binding Value}" And use them in your Click code like this: FrameworkElement theButton = (FrameworkElement)sender; I know this looks like more code but I feel it makes the intent clearer and keeps all the bindings on the Click sender rather than spreading them out across multiple elements and relying on the visual relationship between those elements. Just a suggestion, anyway. |
|
|
Hi Ivan - I thought I would contribute here since you mentioned my project... I took a little different approach in the code for the button click in that I modified the itemsource collection instead of trying to wrestle with the grid. Using your quick and dirty suggestion for the tag property, my button click code pops up an openfile dialog to find an image file, and assigns the filename to the value of the item in the collection, which propagates through to the grid... Public Sub findImage(ByVal sender As Object, ByVal e As RoutedEventArgs) Dim propItem As Mindscape.WpfPropertyGrid.CollectionElement = DirectCast(sender, Button).TagDim dlg As Microsoft.Win32.OpenFileDialog = New Microsoft.Win32.OpenFileDialog()dlg.InitialDirectory = GetImagePath() dlg.DefaultExt = ".jpg" 'Default file extensiondlg.Filter = "JPEG (.jpg)|*.jpg" 'Filter files by extension 'Show open file dialog boxDim result As Boolean = dlg.ShowDialog 'Process open file dialog box results If result = True Then 'Assign the file namepropItem.Source(propItem.IndexedPropertyArguments(0)) = dlg.FileName End IfEnd Sub |
|
|
Hey, I followed the above thread all the way through but I am just not seeing a solution. All I want to do is: I have an object class Container I have a property grid on which I have a datatemplate following the method provided here. I managed to show a textbox with a button in the property grid. Now all I want to do is:
Note that in any one property grid I could have multiple custom properties and I really want each of these to maintain their own specialised objects which I can pass around. Thanks for any help. Ruskin |
|
|
I have got a grubby fix for the time being, would love to hear of an elegant solution if someone already had this problem before. |
|
|
I'm a tiny bit unclear on how your various objects hang together, so let me restate the problem as I have understood it, so you can roast me if I've got the wrong end of the stick. You have a Container object which you are displaying in the grid. Some of Container's properties are strings, but there is special logic associated with each of these properties, and they need to be edited in a dialog, which will be loaded with the appropriate special logic. When the dialog returns, the new string value is the result of calling ToString() on the special logic object [or running an IValueConverter?]. Furthermore, you want to define only one data template and declare only one property editor to handle all of these properties; you do not want to have to declare a property editor or custom template for each individual property. Adapting the technique to populate the dialog with a special logic object instead of with the property value directly, and to call ToString() when the dialog returns, is pretty simple: private void DlgButton_Click(object sender, RoutedEventArgs e) So the problem is where do we get the special logic object (and possibly the IValueConverter) from? And this will be somewhat application-specific. For example, suppose you store your special logic objects in a dictionary keyed by the property name. Then you need some way to make the property info available in the data template's code-behind. A possible way to do this is to use attached properties, as shown further down in the thread: you set the UXLookup.Node attached property on the button to {Binding Property}, and can then go something like: IPropertyInfo property = UXLookup.GetNode(button).Property; If you want to capture the logic objects in XAML then you can do so using an application-level resource dictionary (accessed via Application.Current.Resources) or by passing a collection/dictionary in the PropertyEditor.EditContext member (added after RTM, so requires a nightly build). You could probably also inject the logic objects in your smart editor code, by setting an attached property on the ContentControl in your SetContentTemplate override. It really depends on when and where you have access to these special logic objects. There is also one question to consider at the model level. Are the properties of your container object actually strings -- or might they be better modelled as rich objects, with their own logic, which happen to be presented in the grid as strings? The latter would enable you to use a TypeEditor (or a smart editor) and your editor template would receive the entire rich object, i.e. no need for a separate "special logic object." As I said I am not sure I have precisely understood what you want to do but if the above doesn't help then let me know where I've gone wrong and I'll see if I can suggest something else! |
|
|
Brilliant, nope you understood the question exactly how I intended it to be. The solution seems far more elegant than what I have. And to take up your suggestion on making the actual property contain a rich object is what I was thinking as well as the property grid has no state information, so potentially I'll end up with a Dictionary of properties. And to further complicate things I could have a whole bunch of *Container objects* and each of their properties will need a smart property editor so maintaining that dictionary would be a nightmare. Thanks for that indepth answer. Really appreciate it. Ruskin |
|