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.