使用Xaml创建自定义控件不能作为其他控件的基类
为了能够使创建的自定义控件能够成为其他自定义控件的基类,以便于开发出总体布局具有统一分隔的控件,这里使用代码创建自定义控件。
1. 定义自定义控件
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media.Imaging;
namespace WpfApp1
{
[DefaultProperty("ToolViewContent")]
[ContentProperty("ToolViewContent")]
public class ToolViewBase : UserControl
{
private Grid rootGrid;
private Button runButton;
private Button resetButton;
private StackPanel stackPanel;
private Binding runButtonBinding;
private Binding resetButtonBinding;
private GridSplitter gridSplitter;
private ContentControl contentControl = new ContentControl();
private Binding contentControlBinding;
public ToolViewBase() : base()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
this.rootGrid = new Grid();
this.rootGrid.Margin = new Thickness(5);
this.rootGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });
this.rootGrid.RowDefinitions.Add(new RowDefinition());
this.rootGrid.ColumnDefinitions.Add(new ColumnDefinition());
this.rootGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = GridLength.Auto });
this.rootGrid.ColumnDefinitions.Add(new ColumnDefinition() { MaxWidth = 100});
this.runButtonBinding = new Binding();
this.runButtonBinding.Source = this;
this.runButtonBinding.Path = new PropertyPath(nameof(this.ToolRunCommand));
var runImage = new Image();
runImage.Source = new BitmapImage(new System.Uri("/Images/run.png", System.UriKind.Relative));
this.runButton = new Button
{
Content = runImage,
ToolTip = "Run",
Margin = new Thickness(2)
};
this.runButton.SetBinding(System.Windows.Controls.Primitives.ButtonBase.CommandProperty, this.runButtonBinding);
this.resetButtonBinding = new Binding();
this.resetButtonBinding.Source = this;
this.resetButtonBinding.Path = new PropertyPath(nameof(this.ToolResetCommand));
var resetImage = new Image();
resetImage.Source = new BitmapImage(new System.Uri("/Images/reset.png", System.UriKind.Relative));
this.resetButton = new Button()
{
Content = resetImage,
ToolTip = "Reset",
Margin = new Thickness(2)
};
this.resetButton.SetBinding(System.Windows.Controls.Primitives.ButtonBase.CommandProperty, this.resetButtonBinding);
this.stackPanel = new StackPanel();
this.stackPanel.Orientation = Orientation.Horizontal;
this.stackPanel.Children.Add(this.runButton);
this.stackPanel.Children.Add(this.resetButton);
IAddChild container = (IAddChild)this.rootGrid;
container.AddChild(this.stackPanel);
Grid.SetRow(this.stackPanel, 0);
Grid.SetColumn(this.stackPanel, 0);
Grid.SetRow(this.stackPanel, 0);
Grid.SetColumn(this.stackPanel, 0);
this.contentControl = new ContentControl();
this.contentControlBinding = new Binding();
this.contentControlBinding.Source = this;
this.contentControlBinding.Path = new PropertyPath(nameof(ToolViewContent));
this.contentControl.SetBinding(ContentControl.ContentProperty, this.contentControlBinding);
Grid.SetRow(this.contentControl, 1);
Grid.SetColumn(this.contentControl, 0);
container.AddChild(this.contentControl);
this.gridSplitter = new GridSplitter();
this.gridSplitter.VerticalAlignment = VerticalAlignment.Stretch;
this.gridSplitter.HorizontalAlignment = HorizontalAlignment.Center;
this.gridSplitter.Width = 3;
Grid.SetRow(this.gridSplitter, 0);
Grid.SetColumn(this.gridSplitter, 1);
Grid.SetRowSpan(this.gridSplitter, 2);
container.AddChild(this.gridSplitter);
container = this;
container.AddChild(this.rootGrid);
}
public static readonly DependencyProperty ToolRunCommandProperty = DependencyProperty.Register(nameof(ToolRunCommand), typeof(ICommand), typeof(ToolViewBase));
public ICommand ToolRunCommand
{
get => (ICommand)this.GetValue(ToolRunCommandProperty);
set => this.SetValue(ToolRunCommandProperty, value);
}
public static readonly DependencyProperty ToolResetCommandProperty = DependencyProperty.Register(nameof(ToolResetCommand), typeof(ICommand), typeof(ToolViewBase));
public ICommand ToolResetCommand
{
get => (ICommand)this.GetValue(ToolResetCommandProperty);
set => this.SetValue(ToolResetCommandProperty, value);
}
public static readonly DependencyProperty ToolViewContentProperty = DependencyProperty.Register(nameof(ToolViewContent), typeof(object), typeof(ToolViewBase));
[Bindable(true)]
public object ToolViewContent
{
get => base.GetValue(ToolViewContentProperty);
set => base.SetValue(ToolViewContentProperty, value);
}
}
}
2. 主窗体XAML文件
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" DataContext="{Binding Mode=OneWay, RelativeSource={RelativeSource Self}}" WindowStartupLocation="CenterScreen">
<Grid>
<local:ToolViewBase ToolRunCommand="{Binding RunCommand}" ToolResetCommand="{Binding Path=ResetCommand}">
<TabControl>
<TabItem Header="One"></TabItem>
<TabItem Header="Two"></TabItem>
<TabItem Header="Three"></TabItem>
</TabControl>
</local:ToolViewBase>
</Grid>
</Window>
3. 主窗体后台文件
using System;
using System.Windows;
using System.Windows.Input;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public ICommand RunCommand { get; } = new RelayCommand((o)=>MessageBox.Show("Run"));
public ICommand ResetCommand { get; } = new RelayCommand((o) => MessageBox.Show("Reset"));
}
public class RelayCommand : ICommand
{
private readonly Action<object> m_execute;
private readonly Predicate<object> m_canExecute;
public RelayCommand(Action<object> execute)
{
this.m_execute = execute;
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
this.m_execute = execute;
this.m_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (m_canExecute == null)
return true;
return m_canExecute(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void Execute(object parameter)
{
this.m_execute(parameter);
}
}
}
4. 测试效果