views:

86

answers:

3

Hello,

I'd like to know how to set a custom property of a custom user control by calling a method that would serve as "data provider" for that property.

What I mean is I'd like to write something like this:

<CatsUserControl Cats={FindAllCats} />,

where CatsUserControl is a User Control I created (which has a Property named Cats), and FindAllCats() is a method written in C# that returns a list of Cat objects.

Is this possible?

I appreciate any ideas. Thanks!

EDIT:

The whole thing began because I wanted to be able to assign a list to a property in XAML, the same way you do <Button Content="Value"/> (except, in my case, Value is a more complex type than a string, it's a List<KeyValuePair<String, Boolean>>).

Because I didn't find any way to do that, I thought it might be possible to call a method that returns this list and assign the returned value to the property instead.

Hope that makes things clearer.

+2  A: 

It seems like what you are trying to do is really just databinding?

In other words, you would approach it like this:

<CatsUserControl ItemsSource="{Binding AllCats}" />

Binding to a collection

If you want to bind specifically to a property called Cats you need to create an object that implements INotifyPropertyChanged, I think. (semi-pseudo code follows):

//binding to this public property in the CatsUserControl    
public List<Cat> Cats;


public class BindingToCats : INotifyPropertyChanged
{
    private List<Cat> allCats;

    public List<Cat> AllCats
    {
        get { return allCats; }
        set
        {
            allCats = value;
            OnPropertyChanged("AllCats");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

and then bind to it with your custom usercontrol:

<CatsUserControl Cats="{Binding AllCats, Source={StaticResource BindingToCats}}" />
Timothy Lee Russell
No, that's not what I need.. I edited my question to better describe what I'm after. Sorry if I wasn't clear before.
dsetton
INotifyPropertyChanged implementation is only necessary if you need to UI to track changes made to the property. This is quite a common requirement but isn't absolutely necessary for binding to work. In cases where the property values are readonly or fixed once the object is initialised, INotifyPropertyChanged is not needed.
AnthonyWJones
@AnthonyWJones - Good point...
Timothy Lee Russell
@Timothy: your solution was right all along. The first time I replied I think I was really confused about the problem. Just one remark (really important one): the property (Cats) must be a DependencyProperty. If it's not, binding will not work and you'll get a XamlParseException (AG_E_PARSER_BAD_PROPERTY_VALUE). I didn't know that (I was trying to bind to a regular CLR property), and that's also why I refuted binding as a solution at first. More info on: http://msdn.microsoft.com/en-us/library/cc221408(VS.95).aspx. Thanks again and sorry for the confusion! :)
dsetton
A: 

You ought to be able to do what you're asking by subscribing to events instead of binding directly from the XAML.

Also, you could use a converter, which is described here.

John Fisher
The events idea is good, but I'd like to set all of the control's properties in XAML, so it's clear where those values came from. The converter, OTOH, is a great solution.
dsetton
+1  A: 

What you are probably looking for is a TypeConverter.

Here is an example of how you can set a List< KeyValuePair< String, Boolean>> using a string in attribute syntax in xaml. The Xaml will end up looking something like:

<c:CustomButton Values="Hello World,true; Foo,false; Bar,true" />

The exact syntax of how you want to represent the list of key/value pairs is up to you.

Here is the code necessary to do this:

public class CustomButton : Button
{
    [TypeConverter(typeof(ListOfStringAndBoolPairsTypeConverter))]
    public List<KeyValuePair<String, Boolean>> Values { get; set; }
}

public class ListOfStringAndBoolPairsTypeConverter : TypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
    {
        //TODO: Should add better error handling here.
        var stringValue = (string)value;
        var pairs = stringValue.Split(';').Select(ps => ParsePair(ps));

        var result = new List<KeyValuePair<String, Boolean>>();
        result.AddRange(pairs);
        return result;
    }

    private KeyValuePair<String, Boolean> ParsePair(string pairStringValue)
    {
        var splitString = pairStringValue.Split(',');
        var key = splitString[0];
        var value = Boolean.Parse(splitString[1].Trim());
        return new KeyValuePair<string, bool>(key, value);
    }
}
KeithMahoney
I liked your solution! Not only because it would work in my case, but also because it made me realize that values in XAML don't have to be restricted to a string. I mean, even though ""Hello World,true; Foo,false; Bar,true" is a string, it represents a whole other type to which I can convert it to! The possibilities are endless :D Thanks! Too bad I can't mark two answers as correct..
dsetton