【WPF】创建带内容的自定义控件

使用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. 测试效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhy29563

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值