wpf自定义组件

wpf的学习,xaml写原生的控件,设置样式,或把样式抽离出来放到全局app.xaml,这些百度学习。

 

这里着重讲下,对于一些控件没有的样式怎么自定义一个组件,比如下面讲解自定义一个button实现圆角功能 (目标,给原有button添加新属性,并且要可以在标签绑定此值)。

技术细节,button里面加一个boder,因为boder有圆角属性CornerRadius,可以给自定义button加此属性,属性绑定值时传递到boder标签中。

 

 未完成.....

 

 

 

 

 

 

另外:

1.在xaml写style样式和触发器 (按钮背景颜色触发器要生效必须给button写ControlTemplate)

 触发器: https://www.cnblogs.com/LXLR/p/17653745.html

<Window x:Class="WpfApp3.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="60"></Setter>
            <Setter Property="Height" Value="120"></Setter>
        </Style>

        <Style x:Key="button1_style"  TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="Background" Value="Green"></Setter>
            <Setter Property="FontSize" Value="20"></Setter>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True" >
                    <Trigger.Setters >
                        <Setter Property="FontSize" Value="12"></Setter>
                        <Setter  Property="Foreground" Value="Red"></Setter>
                        <Setter  Property="Background" Value="Red"></Setter>
                    </Trigger.Setters>
                </Trigger>
                <Trigger Property="IsPressed" Value="True">
                    <Trigger.Setters >
                        <Setter Property="FontSize" Value="30"></Setter>
                        <Setter  Property="Foreground" Value="Yellow"></Setter>
                        <Setter  Property="Background" Value="Yellow"></Setter>
                    </Trigger.Setters>
                </Trigger>
            </Style.Triggers>


        </Style>

        <Style TargetType="CheckBox">
            <Style.Triggers>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsChecked" Value="true"/>
                        <Condition Property="Content" Value="HelloWorld"/>
                    </MultiTrigger.Conditions>
                    <MultiTrigger.Setters>
                        <Setter Property="FontSize" Value="40"/>
                        <Setter Property="Foreground" Value="Orange"/>
                        <Setter Property="Background" Value="Red"/>
                    </MultiTrigger.Setters>
                </MultiTrigger>
            </Style.Triggers>
        </Style>


    </Window.Resources>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
            <ColumnDefinition></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions >
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>

        <Button Content="12" Style="{DynamicResource button1_style}"></Button>


        <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal">
            <CheckBox Content="HelloWorld" ></CheckBox>
        </StackPanel>

        <StackPanel Grid.Row="1" Grid.Column="1" Orientation="Horizontal">
            <Button Content="12" Style="{StaticResource button1_style}"></Button>
            <Button Content="123">
                <Button.Style>
                    <Style TargetType="Button">
                        <Setter Property="Background" Value="Red"></Setter>
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="FontSize" Value="16"/>
                        <Setter Property="Width" Value="100"/>
                        <Setter Property="Height" Value="50"/>

                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type Button}">
                                    <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                                        <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                                    </Border>
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>


                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="BlanchedAlmond"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" Value="Cyan"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>

            <Button Content="Click Me">
                <Button.Template>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                    </ControlTemplate>
                </Button.Template>
                <Button.Style>
                    <Style TargetType="Button">
                        <Setter Property="Background" Value="Blue"/>
                        <Setter Property="Foreground" Value="White"/>
                        <Setter Property="FontSize" Value="16"/>
                        <Setter Property="Width" Value="100"/>
                        <Setter Property="Height" Value="50"/>
                        <Style.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Background" Value="Red"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="Background" Value="Cyan"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </Button.Style>
            </Button>


        </StackPanel>


    </Grid>
</Window>

 

2.引入样式文件在项目中(资源字典)

 

 

3.控件模版、组件自定义模板重写  ControlTemplate

            <Button >
                <Button.Content>
                    <StackPanel Orientation="Vertical" Height="90">
                        <Button Content="1" Height="20"></Button>
                        <Button Content="2" Height="20"></Button>
                        <Button Content="3" Height="20"></Button>
                        <Border>
                            <TextBox>text</TextBox>
                        </Border>
                    </StackPanel>                    
                </Button.Content>

            </Button>
            <Button  Content="内容" Width="100" Height="80" Background="Red" FontSize="24" Foreground="BurlyWood">
                <Button.Template>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="border1" Background="{TemplateBinding Background}" Width="{TemplateBinding Width}" Height="{TemplateBinding Height}"  >
                            <TextBlock Text="{TemplateBinding Content}"></TextBlock>
                            <!--ContentPresenter></ContentPresenter-->
                            <!-- 原来组件的内容-->
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter TargetName="border1" Property="Background" Value="Yellow"></Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                    
                </Button.Template>
                
            </Button>

 

4.数据模版  DataTemplate

 

    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            List <Color> test = new List <Color> ();
            test.Add(new Color() { code = "#ffb6c1", name = "钱粉色" });
            test.Add(new Color() { code = "#9400D3", name = "暗紫罗兰" });
            test.Add(new Color() { code = "#E6E6FA", name = "熏衣草淡紫" });
            test.Add(new Color() { code = "#000080", name = "海军蓝" });

            list1.ItemsSource = test;
        }
    }

    public class Color {
        public string name { get; set; }
        public string code { get; set; }
 
    }

<ListBox x:Name="list1"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Border Background="{Binding code}" Width="60" Height="20"> <TextBlock Margin="2,2" Text="{Binding name}"></TextBlock> </Border> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

 

5.绑定

a.两组件值绑定 (Slider和TextBox)

        <StackPanel  Grid.Row="2" Grid.Column="0" Orientation="Vertical">
            <Slider x:Name="slider1" Margin="5"></Slider>
            <TextBox  Text="{Binding ElementName=slider1, Path=Value,Mode=TwoWay}"></TextBox>
        </StackPanel>

 

b.后台model类属性值绑定

 界面要设置 : this.DataContext = viewModel;

界面:

        <StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal">
            <TextBlock>姓名:</TextBlock>
            <TextBox Width="100" Height="30" Text="{Binding name}"></TextBox>
            <TextBlock>密码:</TextBlock>
            <TextBox Width="100" Height="30"  Text="{Binding password}"></TextBox>
        </StackPanel>

界面的cs,代码把dataContext设置上。

    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new mainViewModel() { name="name11", password = "password11"};//给一个初始值
        }
    }

ViewModel,练习view和model, 暂时把实体属性,写到viewModel

namespace WpfApp3.viewModel
{
    class mainViewModel
    {
        public string name { get; set; }
        public string password { get; set; }
    }
}

 

6.通知更新(INotifyPropertyChanged)   即使继承INotifyPropertyChanged接口,使用事件修改ProPertyChangedEventArgs

 a.版本一,不抽离方法写法

    class mainViewModel :INotifyPropertyChanged
    {
        private string _name;
        public string name {
            get { return _name; }
            set {
                _name = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(name)));
            }
        }

        private string _password;
        public string password {
            get { return _password; }
            set
            {
                _password = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("password"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

    }

 

b.版本二,变更抽离到一个方法中 (让多个实体model获得通知能力,就抽离成一个方法)

    class mainViewModel :INotifyPropertyChanged
    {
        private string _name;
        public string name {
            get { return _name; }
            set {
                _name = value;
                OnPropertyChanged();
            }
        }

        private string _password;
        public string password {
            get { return _password; }
            set
            {
                _password = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        //加特性,可以让不加参数自动获取属性名
        public void OnPropertyChanged([CallerMemberName]string propertyName="") {
            PropertyChanged?.Invoke(this , new PropertyChangedEventArgs(propertyName));
        }
    }

7.命令(ICommand)

实例化ICommand接口的,实现类初始化方法传参数(方法名),接口实现类内部再传入一个委托Action在接口执行的方法中调用委托,模版的命令写ICommand类型变量名. 

 RelayCommand.cs

public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Func<object, bool> _canExecute;

        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute == null || _canExecute(parameter);
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }

    }

然后在 mainVM.cs中,定义方法变量,委托调用一个业务方法.

public class MyViewModel : INotifyPropertyChanged
{
    public ICommand MyCommand { get; set; }
 
    public MyViewModel()
    {
        MyCommand = new RelayCommand(ExecuteCommand); //初始化时把命令变量和方法,关联到一起
    }

    //模板为MyConnand命令,业务执行方法为ExecuteCommand   
    private void ExecuteCommand(object parameter)
    {
        // 业务执行操作
    }
 
    // 实现INotifyPropertyChanged接口的代码省略
}

 

8.mvvm框架 (MVVMLight和)

 

posted @ 2024-06-25 13:36  与f  阅读(19)  评论(0编辑  收藏  举报