Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

wpf binding collection property in UserControl

Tags:

c#

wpf

xaml

I have a custom UserControl, which contains collection of custom objects.

public class Question : FrameworkElement
{
    public readonly static DependencyProperty FullNameProperty =
        DependencyProperty.Register("FullName", typeof(string), typeof(Question));

    public readonly static DependencyProperty ShortNameProperty =
        DependencyProperty.Register("ShortName", typeof(string), typeof(Question));

    public readonly static DependencyProperty RecOrderProperty =
        DependencyProperty.Register("RecOrder", typeof(int), typeof(Question));

    public readonly static DependencyProperty AnswerProperty =
        DependencyProperty.Register("Answer", typeof(string), typeof(Question));

    public string FullName
    {
        get { return (string)GetValue(FullNameProperty); }
        set { SetValue(NameProperty, value); }
    }

    public string ShortName
    {
        get { return (string)GetValue(ShortNameProperty); }
        set { SetValue(ShortNameProperty, value); }
    }

    public string Answer
    {
        get { return (string)GetValue(AnswerProperty); }
        set { SetValue(AnswerProperty, value); }
    }

    public int RecOrder
    {
        get { return (int)GetValue(RecOrderProperty); }
        set { SetValue(RecOrderProperty, value); }
    }
}

In my Control code-behind I have

public readonly static DependencyProperty QuestionsProperty =
        DependencyProperty.Register("Questions", typeof(ObservableCollection<Question>), typeof(FormQuestionReportViewer), 
        new PropertyMetadata(new ObservableCollection<Question>()));


     public ObservableCollection<Question> Questions
     {
        get { return GetValue(QuestionsProperty) as ObservableCollection<Question>; }
        set { SetValue(QuestionsProperty, value); }
     }

And in xaml markup I can define my control like this

    <custom:CustomControl>
        <custom:CustomControl.Questions>
            <custom:Question FullName="smth text" ShortName="smth text" RecOrder="1" Answer="Yes" />
            <custom:Question FullName="smth text" ShortName="smth text" RecOrder="2" Answer="Yes" />
        </custom:CustomControl.Questions>          
    </custom:CustomControl>

It's works well, but I want to make binding my collection property in xaml like this

    <custom:CustomControl>
        <custom:CustomControl.Questions Items="{binding Path=Questions}">
            <custom:Question FullName="{binding Name}" ShortName="{binding ShortName}" RecOrder="{binding RecOrder}" Answer={binding Answer}" /> 
        </custom:CustomControl.Questions>          
    </custom:CustomControl>

How I can make that binding?

like image 832
roguepnz Avatar asked Sep 06 '11 14:09

roguepnz


1 Answers

You would have to expose two separate properties, much like an ItemsControl which has an Items and ItemsSource property. It looks like you want to be able to add items using a binding and explicitly by adding to your collection. This behavior would differ from an ItemsControl, which only allows you to use the Items or ItemsSource property, but not both at the same time.

There is nothing preventing you from adding support for both ways of specifying items though, but it would be more work on your part.

First, you'd need a DependencyProperty, such as IEnumerable QuestionsSource, which you could bind to:

public readonly static DependencyProperty QuestionsSourceProperty =
    DependencyProperty.Register("QuestionsSource",
        typeof(IEnumerable),
        typeof(FormQuestionReportViewer), 
        new PropertyMetadata(null));

 public IEnumerable QuestionsSource
 {
    get { return GetValue(QuestionsSourceProperty) as IEnumerable; }
    set { SetValue(QuestionsSourceProperty, value); }
 }

second, you would need a regular CLR property, such as ObservableCollection<Question> Questions, which you could add items to explicitly:

private ObservableCollection<Question> questions = new ObservableCollection<Question>();
public ObservableCollection<Question> Questions
 {
    get { return questions; }
 }

Then you could use these properties like so:

<custom:CustomControl QuestionsSource="{Binding Path=Questions}">
    <custom:CustomControl.Questions>
        <custom:Question FullName="{Binding Name}" ShortName="{Binding ShortName}" RecOrder="{Binding RecOrder}" Answer={Binding Answer}" /> 
    </custom:CustomControl.Questions>          
</custom:CustomControl>

The extra work comes when you want to get the full list of items. You'd need to union the two collections into a single collection. This unified collection would be exposed as a third property, which returns a read-only collection.

like image 192
CodeNaked Avatar answered Sep 20 '22 00:09

CodeNaked