locked
Custom PropertyValueEditor: Problem with ExpressionTextBox in property grid, binding works only in one way RRS feed

  • Question

  • I need to customize editation of an InArgument<> inside property grid. I want to keep the default "Enter VB Expression" editor to support advanced scenarios and also add something like combo box to speed up entering simple values.

    I started with PropertyGridExtensibility samle from the WF_WCF_Samples


    Here is the template I use in custom PropertyValueEditor:

    <ResourceDictionary 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
                 xmlns:loc="clr-namespace:Microsoft.Samples.Activities.Designer.PropertyGridExtensibility"
                xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
                xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation" 
                xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
                xmlns:s="clr-namespace:System;assembly=mscorlib"
        >
        <sapc:ArgumentToExpressionConverter x:Key="ArgumentToExpressionConverter" />
        <sapc:ModelPropertyEntryToOwnerActivityConverter x:Key="ModelPropertyEntryToOwnerActivityConverter" />
        <loc:DoubleConverter x:Key="DoubleConverter" />
        <DataTemplate x:Key="TestDoubleEditor">
            <StackPanel >
                <Slider Minimum="0" Maximum="100" Value="{Binding Mode=TwoWay, Path=Value, Converter={StaticResource DoubleConverter}}"/>
                <TextBox Text="{Binding Path=Value, Converter={StaticResource DoubleConverter}}" IsEnabled="False"/>
                <sapv:ExpressionTextBox 
                    ExpressionType="s:Double"
                    Expression="{Binding Path=Value, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In, Mode=TwoWay}"
                    OwnerActivity="{Binding Path=ParentProperty, Converter={StaticResource ModelPropertyEntryToOwnerActivityConverter}}"                
                    HintText="Enter vb Expr"
                />
            </StackPanel>
        </DataTemplate>
    </ResourceDictionary>
    
    


    Here is code of the custom editor:

        class CustomInlineEditor : PropertyValueEditor
        {
    
            public CustomInlineEditor()
            {
                Uri uri = new Uri("/SampleActivities;component/ResourceDictionary.xaml",System.UriKind.Relative);
                ResourceDictionary rd = (ResourceDictionary)Application.LoadComponent(uri);
                this.InlineEditorTemplate = rd["TestDoubleEditor"] as DataTemplate;
            }
        }
    
    

    And my DoubleConverter (not so important for my question):

        public class DoubleConverter : IValueConverter
        {
            public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                InArgument<double> inArg = value as InArgument<double>;
                if (inArg != null)
                {
                    Activity<double> expression = inArg.Expression;
                    VisualBasicValue<double> vbexpression = expression as VisualBasicValue<double>;
                    Literal<double> literal = expression as Literal<double>;
                    if (literal != null)
                    {
                        return literal.Value;
                    }
                    else if (vbexpression != null)
                    {
                        return vbexpression.ExpressionText;
                    }
                    //add handling for more expression subclasses here...
                }
                return null;
            }
    
            public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                Literal<double> vbArgument = new Literal<double>((double)value);
                return new InArgument<double>(vbArgument);
            }
        }
    
    


    So I can enter double value either by the slider or by the ExpressionTextBox. Slider shows and allows to edit simple values. If there is some complex VB expression, slider shows 0 - Thats fine for me.

    I can use ExpressionTextBox to enter VB expressions. But here is the problem: I can only enter an expression or a value, but I don't see what I entered. For example when I enter a value, change focus away and back, the ExpressionTextBox is empty. Also when I enter a value via the slider, the ExpressionTextBox doesn't update. Something wrong with binding or with the ArgumentToExpressionConverter convertor?

    Thank you for your help.
    Monday, March 8, 2010 4:28 PM

Answers

  • Ah, gotcha.

    OK, so what you want to use is the ArgumentToExpressionModelItemConverter.  Try out the following snippet:



    <sapc:ArgumentToExpressionModelItemConverter x:Key="ArgumentToExpressionModelItemConverter" />

    ...


    <sapv:ExpressionTextBox.Expression>

    <MultiBinding Mode="TwoWay" Converter="{StaticResource ArgumentToExpressionModelItemConverter}" ConverterParameter="In" >

    <Binding Path="PropertyValue.Value" Mode="TwoWay"/>

    <Binding Path="PropertyValue.ParentProperty" Mode="OneWay" />

    </MultiBinding>

    </sapv:ExpressionTextBox.Expression>


    Hope this helps,
    -Eric

    • Marked as answer by JanKrcek Tuesday, March 16, 2010 9:29 AM
    Monday, March 15, 2010 6:58 PM

All replies

  • Sorry for the slow reply.

    You need to set a DataContext on your StackPanel.  Try out the following xaml instead and see if that unblocks you (Bolded parts are changed from your code).

    <

     

     

     

    sapc:ModelPropertyEntryToModelItemConverter x:Key="PropToMod" />

    <StackPanel DataContext="{Binding Converter={StaticResource ResourceKey=PropToMod}>
                <Slider Minimum="0" Maximum="100" Value="{Binding Mode=TwoWay, Path=Value, Converter={StaticResource DoubleConverter}}"/>
                <TextBox Text="{Binding Path=Value, Converter={StaticResource DoubleConverter}}" IsEnabled="False"/>
                <sapv:ExpressionTextBox
                    ExpressionType="s:Double"
                    Expression="{Binding Path=ModelItem.InArg, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In, Mode=TwoWay}"
                    OwnerActivity="{Binding Path=ModelItem}}"               
                    HintText="Enter vb Expr"
                />


    Hope this helps,
    Eric
    Wednesday, March 10, 2010 7:10 PM
  • Thank you for your answer.
    When I move the DataContext="{Binding Converter={StaticResource ResourceKey=PropToMod} from the StackPanel to ExpressionTextBox it works.

    but there is a problem with this approach. I'm writing editor for a property type, not for whole activity. I don't have the knowledge about how the property is named, because I want to reuse the property editor for multiple properties with possibly different names.

    So this is bad for me: Expression="{Binding Path=ModelItem.InArg
    Monday, March 15, 2010 9:57 AM
  • Ah, gotcha.

    OK, so what you want to use is the ArgumentToExpressionModelItemConverter.  Try out the following snippet:



    <sapc:ArgumentToExpressionModelItemConverter x:Key="ArgumentToExpressionModelItemConverter" />

    ...


    <sapv:ExpressionTextBox.Expression>

    <MultiBinding Mode="TwoWay" Converter="{StaticResource ArgumentToExpressionModelItemConverter}" ConverterParameter="In" >

    <Binding Path="PropertyValue.Value" Mode="TwoWay"/>

    <Binding Path="PropertyValue.ParentProperty" Mode="OneWay" />

    </MultiBinding>

    </sapv:ExpressionTextBox.Expression>


    Hope this helps,
    -Eric

    • Marked as answer by JanKrcek Tuesday, March 16, 2010 9:29 AM
    Monday, March 15, 2010 6:58 PM
  • Thanks, this is it! ;)

    Just for completeness, here is the whole template code:

    <ResourceDictionary 
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:loc="clr-namespace:Microsoft.Samples.Activities.Designer.PropertyGridExtensibility"
                xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation" 
                xmlns:sapc="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"
                xmlns:s="clr-namespace:System;assembly=mscorlib"
        >
        <sapc:ModelPropertyEntryToOwnerActivityConverter x:Key="ModelPropertyEntryToOwnerActivityConverter" />
        <sapc:ArgumentToExpressionModelItemConverter x:Key="ArgumentToExpressionModelItemConverter" />
        <loc:DoubleConverter x:Key="DoubleConverter" />
        <DataTemplate x:Key="TestDoubleEditor">
            <StackPanel  >
                <Slider Minimum="0" Maximum="100" Value="{Binding Mode=TwoWay, Path=Value, Converter={StaticResource DoubleConverter}}"/>
                <TextBox Text="{Binding Path=Value, Converter={StaticResource DoubleConverter}}" IsEnabled="False"/>
                <sapv:ExpressionTextBox 
                    ExpressionType="s:Double"                
                    OwnerActivity="{Binding Path=ParentProperty, Converter={StaticResource ModelPropertyEntryToOwnerActivityConverter}}"                
                    HintText="Enter vb Expr"
                >
                    <sapv:ExpressionTextBox.Expression>
                        <MultiBinding Mode="TwoWay" Converter="{StaticResource ArgumentToExpressionModelItemConverter}" ConverterParameter="In" >
                            <Binding Path="Value" Mode="TwoWay"/>
                            <Binding Path="ParentProperty" Mode="OneWay" />
                        </MultiBinding>
                    </sapv:ExpressionTextBox.Expression>
                </sapv:ExpressionTextBox>
            </StackPanel>
        </DataTemplate>
    </ResourceDictionary>
    

    And what currently says MSDN help about ArgumentToExpressionModelItemConverter

    Remarks

    This converter is used internally by the Workflow Designer and is not recommended for use in your code.

    ;) (better help would be great)

     



    Tuesday, March 16, 2010 9:36 AM
  • Hi, I wrote up a blog post on this, http://blogs.msdn.com/cathyk/archive/2010/03/22/using-an-expressiontextbox-in-a-custom-property-editor.aspx. I asked our doc guy to fix up the docs to reflect the actual usage, I will be sure to file a bug to track. Thanks
    Friday, March 26, 2010 6:11 PM