WPF自定义按钮最好的办法 [英] wpf custom button best approach

查看:181
本文介绍了WPF自定义按钮最好的办法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个自定义的按钮里面WPF。当然,该按钮将是一个用户控件,它会包含很多视觉元素(如中风,高光,阴影,光晕,图像等)。

I want to create a custom Button inside WPF. Of course, the button will be an UserControl and it will contain many visual elements (like stroke, highlight, shadow, glow, images etc.).

问题是,如果我使用DependencyProperties和XAML绑定他们,我将无法看到在设计时的结果(我试过实现IsInDesignMode方法,但由于某种原因,我无法理解我的VS刚刚崩溃时,我用这个用户控件的方法,否则它只是罚款),这绝对不是好。

The problem is that if I use DependencyProperties and bind them in XAML I won't be able to see the result at DesignTime (I've tried to implement IsInDesignMode method but for a certain reason that I can't understand my VS just crashes when I use this method on UserControls, otherwise it works just fine) and this is definitely not good.

因此​​,我想都没有使用XAML,做我背后的code所有的工作。

So I am thinking about not using XAML at all and do all my work in the code behind.

你们觉得呢?

推荐答案

和你一样,当我开始使用,并想了解如何/回事,并使用模板的,花了大量的试验和错误的。希望我的研究和一些一步一步的组件可以帮助您自定义自己的喜好,知道那里的东西是从哪里来的。

Like you, when I was getting started and wanted to understand how / what was going on and working with templates, it took a lot of trial and error. Hopefully my research and some step-by-step components can help you customize to your liking and KNOWING where things are coming from.

首先,试图了解一个新的模板式会工作的时候,我创建了一个简单的单机WPF应用程序(AMS)为我的任何操纵样式。这样一来,我没有永远等待,看看会是什么样的东西试/错误过程中与我的主要项目和主题的其余部分。

First, when trying to understand how a new "template style" will work, I created a simple stand-alone WPF app ("AMS") for my Any Manipulating Styles. This way, I don't have to wait forever to see what something will look like during trial / error with the rest of my primary project and themes.

从这一点,我创建了一个新的WPF窗口称为TestingStyles。保存/编译,运行没有问题。

From that, I created a new WPF Window called "TestingStyles". Save/Compile, run, no problem.

现在,在TestingStyles窗口的VIEW code,我已经把一切我与自定义类玩....为了显示一步一步的,我创建了以下

Now, in the "VIEW CODE" of the TestingStyles window, I have put whatever I am playing with for a custom class... To help show the step-by-step, I've created the following:

namespace AMS
{
    /// <summary>
    /// Interaction logic for TestingStyles.xaml
    /// </summary>
    public partial class TestingStyles : Window
    {
        public TestingStyles()
        {
            InitializeComponent();
        }
    }

    // Enumerator for a custom property sample...
    public enum HowToShowStatus
    {
        ShowNothing,
        ShowImage1
    }


    public class YourCustomButtonClass : Button
    {
        public YourCustomButtonClass()
        {
            // auto-register any "click" will call our own custom "click" handler
            // which will change the status...  This could also be done to simplify
            // by only changing visibility, but shows how you could apply via other
            // custom properties too.
            Click += MyCustomClick;
        }

        protected void MyCustomClick(object sender, RoutedEventArgs e)
        {
            if( this.ShowStatus == HowToShowStatus.ShowImage1 )
                this.ShowStatus = HowToShowStatus.ShowNothing;
            else
                this.ShowStatus = HowToShowStatus.ShowImage1;
        }


        public static readonly DependencyProperty ShowStatusProperty =
              DependencyProperty.Register("ShowStatus", typeof(HowToShowStatus),
              typeof(YourCustomButtonClass), new UIPropertyMetadata(HowToShowStatus.ShowNothing));

        public HowToShowStatus ShowStatus
        {
            get { return (HowToShowStatus)GetValue(ShowStatusProperty); }
            set { SetValue(ShowStatusProperty, value); }
        }
    }

}

正如你可以看到,自定义按钮类的,我都不得不默认TestingStyles外底:窗口申报...所以它都在同一个项目。

As you can see, the custom "Button" class, I have at the bottom outside the default TestingStyles : Window declaration... so its all in the same "Project".

在此XAML示例,我参考了TaskComplete.png图形文件(这应该只是样品而言,直接添加到项目中。即使一个简单的笑脸样品的目的)。
因此,即使通过使用Microsoft Paint和绘图与眼睛和微笑圈建立这样一个简单的.png文件...。保存到在根项目(进入路径的东西后,搞不定在前)。

In this XAML sample, I make reference to a "TaskComplete.png" graphic file (which should just for sample purposes, add directly to the project... Even if a simple smiley face for sample purposes). So, create such a simple .png file... even by using Microsoft Paint and drawing a circle with eyes and smile. Save into the project at the root (get into pathing stuff later, get it working first).

保存并重新编译项目,所以项目公开知道新的阶级(按钮)是什么,当你开始定义XAML模板。

Save and recompile the project, so the project knows publicly what the new "class" (button) is when you start to define the XAML template.

现在,回到TestingStyles设计师,让它进入画面分割,所以你可以同时看到设计师和XAML标记......和Just用以下内容替换...

Now, back to the TestingStyles designer and get it into split screen so you can see both the designer and the XAML markup... and Just replace with the following...

<Window x:Class="AMS.TestingStyles"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:AMS"
        Title="TestingStyles" Height="300" Width="300" >

    <Window.Resources>
        <!-- Build a "Style" based on an anticpated target control type of YourCustomButtonClass.
            per the "my:" reference, the "my" is an "alias" to the xmlsn:my in the declaration above,
            so the XAML knows which library to find such control.  In this case, I've included within
            the actual forms's 'View Code' as a class at the bottom.  

            As soon as you assign an "x:Key" reference, its like its telling XAML to make this a PRIVATE
            style so you don't reference it explicitly (yet)
        -->
        <Style TargetType="my:YourCustomButtonClass" x:Key="keyYourCustomButtonClass">
            <!-- put whatever normal "settings" you want for your common look / feel, color -->
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Padding" Value="0,0,1,1"/>
            <Setter Property="Width" Value="100" />
            <Setter Property="Height" Value="30" />

            <!-- Now, for the template of the button.  Things can get really crazy here
              as you are now defining what you want the "button" to look like, borders, 
              content, etc. In this case, I have two borders to give the raise/sunken effect 
              of a button and it has its own colors -->
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button" >
                        <!-- The x:Name references used during triggers to know what it is "applying" changes to -->
                        <Border x:Name="BorderTopLeft"
                                BorderBrush="Gainsboro" 
                                BorderThickness="0,0,1.5,1.5">

                            <Border x:Name="BorderBottomRight"
                                BorderBrush="Gray" 
                                BorderThickness="1.5,1.5,0,0">
                                <!-- Now, what control  type do you want the button to have... 
                                    Ex: You could use a grid (as I have here), stack panels, etc -->
                                <Grid Background="LightBlue" >
                                    <!-- I'm defining as two columns wide, one row tall.  
                                        First column fixed width 20 pixels example for an image -->
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="20px" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>
                                    <Grid.RowDefinitions>
                                        <RowDefinition />
                                    </Grid.RowDefinitions>

                                    <!-- Now, create the controls I want available within my "template".
                                        when assigned with "x:Name", thats like a property withing the template
                                        that triggers can associate and update to. -->
                                    <Image x:Name="btnImage" 
                                        Grid.Row="0" Grid.Column="0"
                                        Stretch="None"
                                        VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                                        Source="TaskComplete.png"
                                        Visibility="Visible" />

                                    <!-- and also have the text for the button to show the user -->
                                    <TextBlock x:Name="txtNewBtn" 
                                        Grid.Row="0" Grid.Column="1"
                                        Padding="5"
                                        HorizontalAlignment="Left"
                                        VerticalAlignment="Center"
                                    Text="{TemplateBinding Content}" />
                                    <!-- The "{TemplateBinding Content}" means to set the text based on 
                                        the "CONTENT" property of the original button and not use a fixed value -->
                                </Grid>
                            </Border>
                        </Border>
                        <!-- Now, some triggers for the button itself... some can be property based, others data-based -->
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsPressed" Value="true">
                                <!-- What properties do we want to change when user CLICKS
                                    on the button, give the "EFFECT" of click down/up by
                                    changing the "Margin" and border thicknesses...  -->
                                <Setter Property="Margin" Value="1,1,0,0"/>
                                <!-- Notice the "TargetName" below referring to the x:Name I've applied in template above 
                                    so when the user clicks on the button, it changes the border thickness properties of
                                    each to give the effect of a normal button clicking.  I'm widening one border, shrinking other -->
                                <Setter TargetName="BorderTopLeft" Property="BorderThickness" Value="2.5,2.5,0,0"/>
                                <Setter TargetName="BorderBottomRight" Property="BorderThickness" Value="0,0,.5,.5"/>
                            </Trigger>

                            <!-- Here, I have a custome property on the class for "ShowStatus".  The binding is to itself
                                regardless of how many instances of this type of "button" are on a given form 
                                First trigger happens when the value is changed to "ShowNothing", but can also change 
                                when set to "ShowImage1" or other as you may need applicable
                            -->
                            <DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowNothing">
                                <Setter TargetName="btnImage" Property="Visibility" Value="Hidden"/>
                            </DataTrigger>
                            <DataTrigger Binding="{Binding Path=ShowStatus, RelativeSource={RelativeSource Self}}" Value="ShowImage1">
                                <Setter TargetName="btnImage" Property="Visibility" Value="Visible"/>
                            </DataTrigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!-- NOW, we can expose any instance of "YourCustomButtonClass" button to use the style based on definition above 
            any instance of such YourCustomButtonClass will automatically reflect this style / look -->
        <Style TargetType="my:YourCustomButtonClass" BasedOn="{StaticResource keyYourCustomButtonClass}" />

    </Window.Resources>

    <Grid>
        <my:YourCustomButtonClass Content="Button" VerticalAlignment="Top" ShowStatus="ShowImage1" />
    </Grid>
</Window>

这应该给你一个很好的快速启动,以确定自己的模板和元素是如何开始绑在一起。一旦这个样本正在运行,为你改变任何颜色,边距,填充等的模板,你会马上看到的视觉冲击该组件对控制权。

This should give you a great jump-start to defining your own templates and how the elements start to tie together. Once this sample is running, as you change any colors, margins, padding, etc to the template, you'll immediately see the visual impact that component has on the control.

有情趣,不靠墙太多碰你的头...

Have fun and don't bang your head too much against the wall...

顺便说一句,这一次是工作,那么你可以采取内的样式元素的东西。

BTW, once this is working, then you can take the style element stuff within the

<Window.Resources>
</Window.Resources> 

和把它变成一个Windows资源字典,使其全局到您的项目,而不是眼前这个测试表单。

and put it into a Windows Resource Dictionary to make it global to your project instead of just this test form.

这篇关于WPF自定义按钮最好的办法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆