samc
Topic Author
Posts: 74
Joined: 21 Aug 2019, 19:22

Specifying resource keys using data binding

12 Sep 2022, 19:47

Hello!

I've been struggling with the proper way to setup a map system we've created in Noesis.

The basics are this: we have a bunch of different icons we want to display on the map: stores, monsters, other points of interest. This pretty much comes down to a list "icons" that have this type of data:
- what type of icon is it
- where is it (position, rotation)

We want to create vector icons for the map. So, up until now, we've split the icons into different lists based on the "type" if the icon. Then, we have a data template for each "type" of icon hat has it's own <Path> element that shows the icon.

The thing that is getting annoying is that now we have so many different lists of "types" of icons, and it seems somewhat silly as these are all 90% the same with just the <Path> data differing.

So, I started looking at an experiment of moving the "paths" into a separate name shared resource. That seemed to work ok:
<Path x:Key="StoreIcon" Data="..." />
<Path x:Key="MonsterIcon" Data="..." />
and then i could refer to the path from a data template:
   <Path Data="{Binding Source={StaticResource StoreIcon}, Path=Data}" />
So that all seemed to work -- but now what I really want to do is instead of explicitly specifying "StoreIcon", I want that data to be bound dynamically. Ie, on my "Icon" data model, add a new "IconName" property which would be set to 'StoreIcon' or 'MonsterIcon'. ie something like this:
   <Path Data="{Binding Source={StaticResource {Binding IconName}, Path=Data}" />
However, it doesn't seem like this works..

I ran into this blob post, which seems to be doing even more than what I need, but might solve it:

http://blog.functionalfun.net/2009/12/s ... ta_31.html

The method has to do with creating a converter that converts the string into the proper static resource.

Is that the best way to do this? Or is there another/better method?

thanks,
sam
 
User avatar
sfernandez
Site Admin
Posts: 2995
Joined: 22 Dec 2011, 19:20

Re: Specifying resource keys using data binding

12 Sep 2022, 20:58

Hi Sam,

First of all I think you should be storing Geometries instead of Paths to define the icons:
<Geometry x:Key="StoreIcon">M0,0L10,0....</Geometry>
You want to provide the resource key from the ViewModel, so you need a converter that can get the resource using the provided key:
<Path Data="{Binding IconName, Converter={StaticResource IconResourceConverter}}"/>
The converter should be able to access the dictionary where those icon resources are defined. That can be done in several ways, maybe the dictionary can be accessed globally (they are part of the Application Resources), or the converter loads the dictionary.

The blog post you mentioned uses a custom MarkupExtension that internally sets in the target property a MultiBinding with a converter that receives the target element and the resource key, so it can just do a FindResource on the specified target element.

Please let me know if you find any trouble with this.
 
samc
Topic Author
Posts: 74
Joined: 21 Aug 2019, 19:22

Re: Specifying resource keys using data binding

13 Sep 2022, 23:12

Thanks for the pointers! I was able to get this all working.

For future reference to anyone who runs into this thread, here's where I ended up:

I put all my "geometry" into a resource dictionary:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
	<Geometry x:Key="StoreIcon">...</Geometry>
	<Geometry x:Key="MonsterIcon">...</Geometry>
</ResourceDictionary>
I then merged that into the global App resource dictionary.

Then, my converter ended up looking like this:
class ResourceNameConverter : IValueConverter
{
    private ResourceDictionary _resourceDictionary;
    public ResourceDictionary ResourceDictionary
    {
        get => _resourceDictionary;
        set => _resourceDictionary = value;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
#if NOESIS
        if (value is string strValue && !string.IsNullOrEmpty(strValue))
        {
            LoadResourceDictionary();

            if (_resourceDictionary != null && _resourceDictionary.Contains(strValue))
            {
                return _resourceDictionary[strValue];
            }
        }
        return value;
#else
        if (value is string strValue)
        {
            LoadResourceDictionary();

            if (_resourceDictionary != null && _resourceDictionary.Contains(strValue))
            {
                return _resourceDictionary[strValue];
            }

            var resources = Application.Current.Resources;
            if (resources != null && resources.Contains(strValue))
            {
                return resources[strValue];
            }
        }
        return null;
#endif
    }

    private void LoadResourceDictionary()
    {
        if (_resourceDictionary != null)
        {
            return;
        }
        
        #if NOESIS
        _resourceDictionary = Noesis.GUI.GetApplicationResources();
        #endif
    }

    public Variant ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
At one point I tried to specify the ResourceDictionary inline, but that broke the blend designer :(. The code above seemed to work well in Noesis as well as in blend designer.

I think the only question I have now, really, is if this is the best way to do this.. or would it be better to use something like styles? I don't know much about styles, but it seems like logically they should be able to solve a similar problem -- ie, I want an icon to show up in my "monster" style vs. the "store" style.. I haven't worked with styles much yet, though, so I'm not sure if it's better or not.

Any suggestions on the style front?

thanks,
sam
 
samc
Topic Author
Posts: 74
Joined: 21 Aug 2019, 19:22

Re: Specifying resource keys using data binding

14 Sep 2022, 02:15

I used pretty much the identical technique to switch to named styles; it all seems to work ok (when the data binding changes, the style is re-evaluated).

It seems like style is more generic in terms of all the things I can do with it, so assuming the performance isn't terrible I"ll probably continue to stick with it.

thanks,
sam
 
User avatar
sfernandez
Site Admin
Posts: 2995
Joined: 22 Dec 2011, 19:20

Re: Specifying resource keys using data binding

14 Sep 2022, 11:12

Using geometry resources is the most simple approach. Styles allow you to specify more things for a Path (like colors, stroke, size...), and there won't be any performance issues. I guess it all depends on what you need. The good thing about the converter is that it doesn't need to change, it is a generic way of applying resources of any type using bindings.

Who is online

Users browsing this forum: Ahrefs [Bot], Semrush [Bot] and 7 guests