简体   繁体   中英

WPF Custom Control for Expander

I am working with WPF and looking for a best approach for creating re-usable expanders that are customized. Specifically the Expander header would remain the same, the content would vary.

The Expander header would have 6 buttons all wired to the same methods, which will be enforced via an interface.

Assume this is Expander 1

在此处输入图片说明

And this is another expander

在此处输入图片说明

The actual content will be text, buttons, whatever. It just has text for demo purposes.

The expander is meant to be used within a User Control, in which I have 44 of them, and don't want to repeat the code all over the place.

At the moment I am using the UserControls like the following in the Window XAML

xmlns:customcontrols="clr-namespace:MyNamespace.Controls;assembly=MyAssembly"

And the actual usage:

<customcontrols:FlexExtend ..... />

And inside each User Control I am using expander like this

<Expander Style="{StaticResource ModToolPanelStyle}"  Background="#403F3B"  Name="toolExpand" Header="{x:Static properties:Resources.AdductionAbduction_Label}" Collapsed="toolExpand_Collapsed" Expanded="toolExpand_Expanded">

....... all the inside body stuff

</expander>

Right now I'm looking at having to replicate the code 44 times, one for each expander in each of the 44 user controls that contain the an expander. Is there a way in WPF to make this a custom control that would have the buttons and everything? I'm think no since it wouldn't be able to be bound there for the on click?

UPDATE:

As suggested I created a DataTemplate in a seperate XAML.

<DataTemplate x:Key="DesignExpanderHeaderTemplate">
        <DockPanel>
            <TextBlock Name="ModName"
                       Foreground="White"
                       Text="Balls">
            </TextBlock>
            <Button Name="MoveUpButton"
                    Content="MoveUp"
                    Width="80"
                    Height="25">
            </Button>
        </DockPanel>
    </DataTemplate>

However now I am having issues binding the button from the user control:

var button = toolExpand.HeaderTemplate.FindName("MoveUpButton", toolExpand) as Button;
        button.Click += delegate (object sender, RoutedEventArgs args)
        {
            MessageBox.Show("The button has been pressed");
        };

The button is always null, so it is not able to find it.

This is how the XAML looks

<Expander Style="{StaticResource ModToolPanelStyle}"  
                  Background="#403F3B"  
                  x:Name="toolExpand" 
                  HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}" 
                  Collapsed="toolExpand_Collapsed" 
                  Expanded="toolExpand_Expanded">

Following the guidance of user2455627 I was able to get this working. The main key was the following:

RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}

My datatemplate looks like the following.

<DataTemplate x:Key="DesignExpanderHeaderTemplate">
    <DockPanel>
        <TextBlock Foreground="White"
                   Text="{Binding ModName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
        </TextBlock>
        <Button Command="{Binding MoveUpCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
                Content="MoveUp"
                Width="80"
                Height="25">
        </Button>
        <Button Command="{Binding MoveDownCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
                Content="MoveUp"
                Width="80"
                Height="25">
        </Button>
        <Button Command="{Binding UndoCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
                Content="Undo"
                Width="80"
                Height="25"></Button>
    </DockPanel>
</DataTemplate>

Here is how I am using the data template in the XAML

<Expander Style="{StaticResource ModToolPanelStyle}"  
              Background="#403F3B"  
              x:Name="toolExpand" 
              HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}" 
              Collapsed="toolExpand_Collapsed" 
              Expanded="toolExpand_Expanded">

And here is the relevant code behind:

// Commands
    public RelayCommand MoveUpCommand { get; set; }
    public RelayCommand MoveDownCommand { get; set; }
    public RelayCommand UndoCommand { get; set; }
    public RelayCommand RedoCommand { get; set; }
    public RelayCommand ClearCommnand { get; set; }
    public RelayCommand RemoveCommand { get; set; }

    // Properties
    private string _modName;

// setup ModPanel
        ModName = "Something";
        MoveUpCommand = new RelayCommand(MoveUp);
        MoveDownCommand = new RelayCommand(MoveDown);
        UndoCommand = new RelayCommand(Undo);
        RedoCommand = new RelayCommand(Redo);
        ClearCommnand = new RelayCommand(Clear);
        RemoveCommand = new RelayCommand(Remove);

public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    public string ModName
    {
        get { return _modName; }
        set
        {
            _modName = value;
            OnPropertyChanged();
        }
    }

    public void MoveUp(object obj)
    {
        throw new NotImplementedException();
    }

    public void MoveDown(object obj)
    {
        throw new NotImplementedException();
    }

    public void Undo(object obj)
    {
        throw new NotImplementedException();
    }

    public void Redo(object obj)
    {
        throw new NotImplementedException();
    }

    public void Remove(object obj)
    {
        throw new NotImplementedException();
    }

    public void Clear(object obj)
    {
        throw new NotImplementedException();
    }

    public void PreApply()
    {
        throw new NotImplementedException();
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM