Foreign Keys

Grids for WPF Forum

Posted 14 years ago by United Biosource - United Biosource
Version: 9.1.0507
Avatar
This must be a reasonably common scenario, but what I'm trying to do is to create a custom Editor that can dynamically populate a ComboBox with a list items in a table represented by my object's foreign key value. I could use the Category attribute to mark the Foreign Key fields and then use a Category Editor with a View Model that can deal with the dynamic data lookup, but I'm unsure how to make the CategoryEditor dynamic - for instance, in the sample, you have the Properties hard coded (below), but I won't know the PropertyName until runtime.

<propgrid:CategoryEditor.Properties> <propgrid:CategoryEditorProperty PropertyName="FontFamily" /> <propgrid:CategoryEditorProperty PropertyName="FontSize" />
<propgrid:CategoryEditorProperty PropertyName="FontStyle" />
<propgrid:CategoryEditorProperty PropertyName="FontWeight" />
<propgrid:CategoryEditorProperty PropertyName="Text" />
</propgrid:CategoryEditor.Properties>

Maybe this is totally the wrong approach - any ideas how to accomplish this? My objects are LINQ-to-SQL objects, so I'd like to be able to use the LINQ attributes (e.g., Association) to detect the Foreign Key (rather than having to code Category attributes on all of them).

Also, do you have any examples of using a PropertyGrid DataTemplate with a View Model?

[Modified at 11/11/2009 08:10 PM]

Comments (3)

Posted 14 years ago by United Biosource - United Biosource
Avatar
Alright, well, in the interim, I have done this:

1. Created a ViewModel, ForeignKeyModel, with an ObservableCollection "Items" property:

public ForeignKeyModel()
{
    Items = new ObservableCollection<T>(MyFacadeBase<T, U>.GetFacadeList());
}
2. Created a UserControl (View) called ForeignKeyView.xaml with a dependency property called ForeignKeyProperty, with associated getter/setter. In the setter I have the following code:

public string ForeignKey
{
    get { return (string)GetValue(ForeignKeyProperty); }
    set
    {
        SetValue(ForeignKeyProperty, value);
        if (!String.IsNullOrEmpty(value))
            LoadModel();
        else
            DataContext = null;
    }
}
LoadModel does this:

Type facadeType =
    Type.GetType(String.Format("Namespace.{0}Facade, AssemblyName", ForeignKey));
Type objectType =
    Type.GetType(String.Format("Namespace.{0}, AssemblyName", ForeignKey)));

Type viewModel = typeof(ForeignKeyModel<,>);

Type instantiator = viewModel.MakeGenericType(facadeType, objectType);

DataContext = Activator.CreateInstance(instantiator);
3. Created a DataTemplate that wraps the UserControl and, I thought, links the PropertyGrid value to the ForeignKey property:

    //non-working code
    <DataTemplate x:Key="ForeignKeyTemplate">
        <controls:ForeignKeyView 
            ForeignKey="{Binding DisplayName, RelativeSource={RelativeSource AncestorType={x:Type propgrid:IPropertyDataAccessor}}, Mode=OneWay}"
            />
    </DataTemplate>
4. In the Controller, in the object selection event, link ForeignKey fields to the DataTemplate:

foreach (PropertyInfo prop in CurrentObject.GetType().GetProperties())
{
    AssociationAttribute[] associations = (AssociationAttribute[])
        prop.GetCustomAttributes(typeof(AssociationAttribute), false);

    if (associations != null && associations.Length > 0)
    {
        AssociationAttribute association = associations[0];
        if (association.IsForeignKey)
        {
            DataTemplate fkTemplate = (DataTemplate)_view.FindResource("ForeignKeyTemplate");
            _view.PropertyHost.Properties.PropertyEditors.Add(
                new PropertyEditor
                {
                    PropertyName = prop.Name,
                    ValueTemplate = fkTemplate
                });
        }
    }
}
The ForeignKeyView is definitely being picked up, but its ForeignKey property is never being set, so the ViewModel is never loaded. Shouldn't the DataTemplate be taking care of binding the ForeignKey property?

Thanks.

[Modified at 11/12/2009 04:49 PM]
Posted 14 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Sydney,

When you have more complex examples like this, it's probably best to send a small sample project to our support address. It's usually easier to follow.

But, from the above, you should never add additional code into the getter or setter of a DependencyProperty. Typically, XAML code will set the property directly (using SetValue). You would need to add a "property changed" handler to your DependencyProperty definition.

You can add a category editor that doesn't "consume" any properties, but you would need to know the category name. The CategoryEditorProperty only hides the properties from being displayed normally (i.e. it indicates the category editor will handle them). Your category editor can access or reference any property.

If you are populating the Items/ItemsSource properties on the PropertyGrid, then you can add category editors anywhere you want (in or ourside of categories). Additionally, you can use a custom DataFactory to accomplish the same thing, while still supporting SelectedObject(s) and Properties. It just depends on how you use the PropertyGrid.

Finally, you can define a single PropertyEditor that uses a ValueTemplateSelector (and doesn't define a PropertyType or PropertyName) to dynamically select the ValueTemplate.

Hopefully, this will help steer you in the right direction.


Actipro Software Support

Posted 14 years ago by United Biosource - United Biosource
Avatar
Doh! Of course, I knew that at some point (-: Anyway, that works perfectly. Partly why I posted the code, in case anyone else needs to do the same thing. So, to that end, here's the revised code for the ForeignKeyView:

public static readonly DependencyProperty ForeignKeyProperty =
    DependencyProperty.Register(
            "ForeignKey",
            typeof(string),
            typeof(ForeignKeyView),
            new FrameworkPropertyMetadata(ForeignKeyPropertyChanged)
            );

private static void ForeignKeyPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
    ((ForeignKeyView)sender).LoadModel();
}
The latest build of this product (v24.1.2) was released 0 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.