Question

I am new to custom control creation. I have laid some groundwork for a new custom control based on the Selector class. My understanding was that I should use this class since I needed the control to have an Items collection and the ability to handle selections. I believe that changing the ItemTemplate may have overriden some of this ability because I do not receive the SelectionChanged event at the control level or application level. I would think if I'm right that there is some sort of SelectionRegion XAML tag that I can put the DataTemplate innards into. I have not had luck in finding anything like this. After looking through Google for a while, I am ready to just ask. What am I missing? Below is the ItemTemplate markup. Thanks for any help. Thanks even more if you can tell me why the Text in TextBlock is enclosed in parentheses even though the data isn't.

<Setter Property="ItemTemplate">
    <Setter.Value>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="1">
                <TextBlock Text="{Binding}" Foreground="Black" Background="White" MinHeight="12" MinWidth="50"/>
            </Border>
        </DataTemplate>
    </Setter.Value>
</Setter>

At the request of a commenter, here is the complete XAML for the control so far:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SourceMedicalWPFCustomControlLibrary">
    <Style TargetType="{x:Type local:MultiStateSelectionGrid}">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <WrapPanel/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="ItemTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border BorderBrush="Black" BorderThickness="1">
                        <TextBlock Text="{Binding Code}" Foreground="Black" Background="White" MinHeight="12" MinWidth="50" Padding="2" ToolTip="{Binding Description}"/>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MultiStateSelectionGrid}">
                    <StackPanel HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Background="{TemplateBinding Background}">
                        <ContentPresenter HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0,0,0,0" Content="{TemplateBinding Content}"/>
                        <ItemsPresenter/>
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

And the anemic code-behind as well:

namespace SourceMedicalWPFCustomControlLibrary
{
    public class MultiStateSelectionGridState
    {
        public Brush Background { get; set; }
        public Brush Foreground { get; set; }
        public Brush Border { get; set; }
        public string Text { get; set; }

        public MultiStateSelectionGridState()
        {
            Background = Brushes.White;
            Foreground = Brushes.Black;
            Border = Brushes.Black;
            Text = String.Empty;
        }
    };

    public class MultiStateSelectionGrid : Selector
    {
        public static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register("Content", typeof(object), typeof(MultiStateSelectionGrid),
            new FrameworkPropertyMetadata(null,
                  FrameworkPropertyMetadataOptions.AffectsRender |
                  FrameworkPropertyMetadataOptions.AffectsParentMeasure));

        public object Content
        {
            get { return (object)GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        public static readonly DependencyProperty StatesProperty =
            DependencyProperty.Register("States", typeof(List<MultiStateSelectionGridState>), typeof(MultiStateSelectionGrid),
            new FrameworkPropertyMetadata(new List<MultiStateSelectionGridState>(),
                FrameworkPropertyMetadataOptions.AffectsRender));

        public List<MultiStateSelectionGridState> States
        {
            get { return (List<MultiStateSelectionGridState>)GetValue(StatesProperty); }
            set { SetValue(StatesProperty, value); }
        }

        static MultiStateSelectionGrid()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiStateSelectionGrid), new FrameworkPropertyMetadata(typeof(MultiStateSelectionGrid)));
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.SelectionChanged += new SelectionChangedEventHandler(MultiStateSelectionGrid_SelectionChanged);
        }

        void MultiStateSelectionGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            MessageBox.Show("Hi");
        }
    }
}
Was it helpful?

Solution 2

From reading some full code examples of different controls, I believe my answer is that I am doing this all wrong. Instead, I need to have control that has a Selector like a ListBox in the ControlTemplate. THEN, @JKing 's advice would help me get to where I need to be. The answer to the actual question asked though is the aforementioned change from using Selector as a base class to having a selector in the template for the control. Thanks for the help.

OTHER TIPS

here is what I do. I use the apply template function of the custom control and add a handlerto the selection chnaged event of the control I want.

simple sample here:

public event EventHandler<SelectionChangedEventArgs> YourControlSelectionChanged;

private void Selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (ListSelectionChanged != null) {
        ListSelectionChanged(sender, e);
    }
}

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    //find or declare your control here, the x:name in xaml should be YourControl
    YourControl== this.Template.FindName("YourControl", this) as YourControlType
    YourControl.SelectionChanged += ResultListBox_SelectionChanged;
}

you can then bind to the name of the public event (YourControlSelectionChanged) you declared in your custom control class in xaml.

hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top