扩展器的 WPF 自定义控件
WPF Custom Control for Expander
我正在使用 WPF 并寻找一种最佳方法来创建自定义的 re-usable 扩展器。具体来说,Expander header 将保持不变,内容会有所不同。
Expander header 将有 6 个按钮全部连接到相同的方法,这将通过接口强制执行。
假设这是扩展器 1
这是另一个扩展器
实际内容将是文本、按钮等。它只有用于演示目的的文本。
扩展器是要在用户控件中使用的,我有 44 个,不想到处重复代码。
目前我在 Window XAML
中使用如下所示的用户控件
xmlns:customcontrols="clr-namespace:MyNamespace.Controls;assembly=MyAssembly"
以及实际使用情况:
<customcontrols:FlexExtend ..... />
在每个用户控件中我都使用这样的扩展器
<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>
现在我正在考虑必须将代码复制 44 次,每个扩展器对应 44 个包含扩展器的用户控件中的每个扩展器。 WPF 中有没有一种方法可以使它成为具有按钮和所有内容的自定义控件?我认为不可以,因为点击时它无法绑定到那里?
更新:
按照建议,我在单独的 XAML.
中创建了一个 DataTemplate
<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>
但是现在我在绑定用户控件的按钮时遇到问题:
var button = toolExpand.HeaderTemplate.FindName("MoveUpButton", toolExpand) as Button;
button.Click += delegate (object sender, RoutedEventArgs args)
{
MessageBox.Show("The button has been pressed");
};
按钮始终为空,因此无法找到它。
这就是 XAML 的样子
<Expander Style="{StaticResource ModToolPanelStyle}"
Background="#403F3B"
x:Name="toolExpand"
HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}"
Collapsed="toolExpand_Collapsed"
Expanded="toolExpand_Expanded">
在 user2455627 的指导下,我成功了。主要关键如下:
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
我的数据模板如下所示。
<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>
以下是我在 XAML
中使用数据模板的方式
<Expander Style="{StaticResource ModToolPanelStyle}"
Background="#403F3B"
x:Name="toolExpand"
HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}"
Collapsed="toolExpand_Collapsed"
Expanded="toolExpand_Expanded">
后面的相关代码如下:
// 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();
}
我正在使用 WPF 并寻找一种最佳方法来创建自定义的 re-usable 扩展器。具体来说,Expander header 将保持不变,内容会有所不同。
Expander header 将有 6 个按钮全部连接到相同的方法,这将通过接口强制执行。
假设这是扩展器 1
这是另一个扩展器
实际内容将是文本、按钮等。它只有用于演示目的的文本。
扩展器是要在用户控件中使用的,我有 44 个,不想到处重复代码。
目前我在 Window XAML
中使用如下所示的用户控件xmlns:customcontrols="clr-namespace:MyNamespace.Controls;assembly=MyAssembly"
以及实际使用情况:
<customcontrols:FlexExtend ..... />
在每个用户控件中我都使用这样的扩展器
<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>
现在我正在考虑必须将代码复制 44 次,每个扩展器对应 44 个包含扩展器的用户控件中的每个扩展器。 WPF 中有没有一种方法可以使它成为具有按钮和所有内容的自定义控件?我认为不可以,因为点击时它无法绑定到那里?
更新:
按照建议,我在单独的 XAML.
中创建了一个 DataTemplate<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>
但是现在我在绑定用户控件的按钮时遇到问题:
var button = toolExpand.HeaderTemplate.FindName("MoveUpButton", toolExpand) as Button;
button.Click += delegate (object sender, RoutedEventArgs args)
{
MessageBox.Show("The button has been pressed");
};
按钮始终为空,因此无法找到它。
这就是 XAML 的样子
<Expander Style="{StaticResource ModToolPanelStyle}"
Background="#403F3B"
x:Name="toolExpand"
HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}"
Collapsed="toolExpand_Collapsed"
Expanded="toolExpand_Expanded">
在 user2455627 的指导下,我成功了。主要关键如下:
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}
我的数据模板如下所示。
<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>
以下是我在 XAML
中使用数据模板的方式<Expander Style="{StaticResource ModToolPanelStyle}"
Background="#403F3B"
x:Name="toolExpand"
HeaderTemplate="{StaticResource DesignExpanderHeaderTemplate}"
Collapsed="toolExpand_Collapsed"
Expanded="toolExpand_Expanded">
后面的相关代码如下:
// 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();
}