WPF 使用自定义控件(custom control),资源字典(ResourceDictionary),用户控件(user control),及之间的对比

2023-11-07

最近使用WPF比较多,过来记录一下,对比一下

个人理解usercontrol比较适用于组合控件(比如你想要实现的控件是由多个控件组成的),customCcontrol主要是用来单独重绘控件,如button,datagrid,lable等。customCcontrol修改控件外观的方专式是可属以访问控件本身template的里的控件,然后可以对其修改样式和增加逻辑。

而资源字典更多是通过”Seyle”标签来封装资源。在WPF中我们可以使用Style来设置控件的某些属性值,并使该设置影响到指定范围内的所有该类控件或影响指定的某一控件。

一、创建自定义控件

1、控件后台交互类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfCustomControlLibrary1
{
   
    [TemplatePart(Name = CustomControl1.ElementDateTimeTextBox, Type = typeof(TextBlock))]
    [TemplatePart(Name = CustomControl1.ElementContentTextBox, Type = typeof(TextBlock))]
    public class CustomControl1 : Control
    {
        public CustomControl1()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl1), new FrameworkPropertyMetadata(typeof(CustomControl1)));
            ContentMsg = "Hello World"; 
        }
        private const string ElementDateTimeTextBox = "PART_DateTimeTextBox";
        private const string ElementContentTextBox = "PART_ContentTextBox";
        private const string Elementbutton = "PART_Button"; 
        TextBlock contentMsgTB = null;
        Button button = null;
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
             
            contentMsgTB = GetTemplateChild(ElementContentTextBox) as TextBlock;
            button =  GetTemplateChild(Elementbutton) as Button;
            button.Click += Button_Click;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ContentMsg = "李四";
        }

        /// <summary>
                /// Registers a dependency property as backing store for the Content property
                /// </summary>
        public static readonly DependencyProperty ContentMsgProperty =
      DependencyProperty.Register("ContentMsg", typeof(object), typeof(CustomControl1),
      new FrameworkPropertyMetadata(null ));

        /// <summary>
                /// Gets or sets the Content.
                /// </summary>
                /// <value>The Content.</value>
        public object ContentMsg
        {
            get { return (object)GetValue(ContentMsgProperty); }
            set { SetValue(ContentMsgProperty, value); }
        }  
    }
}


2、样式Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfCustomControlLibrary1">
    <Style TargetType="{x:Type local:CustomControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                    <StackPanel Orientation="Horizontal"> 
                        <TextBlock x:Name="PART_ContentTextBox" Text="{TemplateBinding ContentMsg}"/>
                        <StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Button  Margin="10"  
                                         Grid.Column="0" Grid.Row="0"  Content="1" x:Name="PART_Button"/>
                                <Button  Margin="10" Grid.Column="0" Grid.Row="1"   Content="2" x:Name="PART_Button2"/>
                                <Button  Margin="10"  Grid.Column="0" Grid.Row="2"   Content="3" x:Name="PART_Button3"/> 
                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Button  Margin="10"  Grid.Column="1" Grid.Row="0"   Content="4" x:Name="PART_Button4"/>
                                <Button Margin="10"   Grid.Column="1" Grid.Row="1"   Content="5" x:Name="PART_Button5"/>
                                <Button Margin="10"   Grid.Column="1" Grid.Row="2"   Content="6" x:Name="PART_Button6"/>

                            </StackPanel>
                            <StackPanel Orientation="Horizontal">
                                <Button   Margin="10" Grid.Column="2" Grid.Row="0"   Content="7" x:Name="PART_Button7"/>
                                <Button   Margin="10" Grid.Column="2" Grid.Row="1"   Content="8" x:Name="PART_Button8"/>
                                <Button  Margin="10"  Grid.Column="2" Grid.Row="2"   Content="9" x:Name="PART_Button9"/>

                            </StackPanel>
                        </StackPanel>
                      </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

3、应用

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        xmlns:custom="clr-namespace:WpfCustomControlLibrary1;assembly=WpfCustomControlLibrary1"
        Title="MainWindow" Height="450" Width="800">
 
    <StackPanel>
        <custom:CustomControl1 ContentMsg="{Binding DateTimeMsg,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"  
                               x:Name="mycustom"  HorizontalAlignment="Left" Margin="55,30,0,0" VerticalAlignment="Top"></custom:CustomControl1>
        <Button Content="dsafsdf" Click="Button_Click" Height="40" Width="100" Margin="10"></Button>
    </StackPanel>
</Window>

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WpfCustomControlLibrary1
{
  
    public class MainViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string _DateTimeMsg;
        public string DateTimeMsg
        {
            get
            {
                return _DateTimeMsg;
            }
            set
            {
                _DateTimeMsg = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("DateTimeMsg"));
                }
            }
        }
        private string _ContentMsg;
        public string ContentMsg
        {
            get
            {
                return _ContentMsg;
            }
            set
            {
                _ContentMsg = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("ContentMsg"));
                }
            }
        }
        
    }
}

4、页面访问

可通过依赖属性  MessageBox.Show(this.mycustom.ContentMsg.ToString());

二、资源字典

1、创建资源字典

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                    xmlns:local="clr-namespace:WPFtest"
                    x:Class="WPFtest.DicEvent" >
    <local:RotationManager x:Key="p"></local:RotationManager>
    <local:NumberConverter x:Key="NumberConverter"></local:NumberConverter> 
       <Style TargetType="Button" x:Key="ButtonImage">
        <Setter Property="Background" Value="Transparent" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                   
                    <Grid Background="{TemplateBinding Background}">
                        <StackPanel HorizontalAlignment="Left">
                            <Button Name="my" Click="liClick_Click" Background="Red" Content="点我啊"></Button>
                        </StackPanel>
                        <StackPanel  HorizontalAlignment="Right">
                            <TextBox Name="texbox2" Text="{Binding Source={StaticResource p},Path=Angle,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  Height="50" Width="100"></TextBox>
                            <!--<TextBox Name="texbox2" Text="{Binding RelativeSource={RelativeSource  RotationManager.Angle}}"  Height="50" Width="100"></TextBox>-->
                            <!--<TextBox Name="texbox2" Text="{Binding Source=local:RotationManager.Angle,Path=value, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"  Height="50" Width="100"></TextBox>-->
                            <!--<TextBox Name="texbox1" Text="{TemplateBinding local:RotationManager.Angle}"  Height="50" Width="100"></TextBox>-->
                            <!--<Label Name="texbox1" Content="{TemplateBinding local:RotationManager.Angle,Converter={StaticResource ResourceKey=NumberConverter}}"  Height="50" Width="100"></Label>-->
                        </StackPanel>
                        <ContentPresenter></ContentPresenter>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

2、资源字典后台处理类

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
namespace WPFtest
{
    public partial class DicEvent : ResourceDictionary
    {
        public void liClick_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(((sender as Button).TemplatedParent).GetValue(RotationManager.AngleProperty).ToString());
            ((sender as Button).TemplatedParent).SetValue(RotationManager.AngleProperty, "1111111");
            MessageBox.Show(((sender as Button).TemplatedParent).GetValue(RotationManager.AngleProperty).ToString());

            //省去处理,如果显示,表明调用成功。
            //System.Windows.Forms.MessageBox.Show("点击了资源字典的控件!");

        }
        public void my_MouseEnter(object sender, RoutedEventArgs e)
        {
            System.Windows.Forms.MessageBox.Show("你成功dd了!");

        }

    }

    public class myattach : DependencyObject
    {
        public static string GetGrade(DependencyObject obj)
        {
            return (string)obj.GetValue(GradeProperty);
        }

        public static void SetGrade(DependencyObject obj, string value)
        {
            obj.SetValue(GradeProperty, value);
        }

        public static readonly DependencyProperty GradeProperty =
            DependencyProperty.RegisterAttached("attach", typeof(string), typeof(myattach), new UIPropertyMetadata("isattach"));

    }

   

}


3、数值转换器

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;

namespace WPFtest
{
    [ValueConversion(typeof(int), typeof(string))]
    public class NumberConverter : IValueConverter
    {
        //源属性传给目标属性时,调用此方法ConvertBack
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int c = System.Convert.ToInt32(parameter);

            if (value == null)
                throw new ArgumentNullException("value can not be null");

            int index = System.Convert.ToInt32(value);
            if (index == 0)
                return "Blue";
            else if (index == 1)
                return "Red";
            else
                return "Green";
        }

        //目标属性传给源属性时,调用此方法ConvertBack
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    } 
}

三、用户控件

1、创建控件模板

<UserControl x:Class="XXX.自定义控件.MyNumericUpDown"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:XXX.自定义控件"
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="120">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition Width="40*"/>
            <ColumnDefinition Width="40*"/>
        </Grid.ColumnDefinitions>

        <TextBox Name="TextBox_Num" Grid.Column="0" Text="1" FontSize="20" TextAlignment="Center" MinWidth="40" VerticalContentAlignment="Center"/>
        <Button Name="Button_Add" Grid.Column="1" Content="加" Click="Button_Add_Click" Background="Aqua"/>
        <Button Name="Button_Sub" Grid.Column="2" Content="减" Click="Button_Sub_Click" Background="Aqua"/>
        
    </Grid>
</UserControl>

2、编写后台代码

/// <summary>
    /// MyNumericUpDown.xaml 的交互逻辑
    /// </summary>
    public partial class MyNumericUpDown : UserControl
    {

        /// <summary>
        /// 当前值
        /// </summary>
        public int Num
        {
            get
            {
                int value = 0;
                this.Dispatcher.Invoke(new Action(() =>
                    value = Convert.ToInt32(this.TextBox_Num.Text.Trim())
                ));
                return value;
            }
            set
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    this.TextBox_Num.Text = value.ToString();
                }));                
            }
        }

        public MyNumericUpDown()
        {
            InitializeComponent();
        }
        
        private void Button_Add_Click(object sender, RoutedEventArgs e)
        {
            int num = int.Parse(this.TextBox_Num.Text.Trim());
            if (num > 0)
            {
                this.TextBox_Num.Text = (num + 1).ToString();
            }
        }

        private void Button_Sub_Click(object sender, RoutedEventArgs e)
        {
            int num = int.Parse(this.TextBox_Num.Text.Trim());
            if (num > 0)
            {
                if ((num - 1) == 0)
                    return;
                this.TextBox_Num.Text = (num - 1).ToString();
            }
        }
    }

三、使用控件

xmlns:z="clr-namespace:XXX.自定义控件"  //Windows标签中声明命名空间
<z:MyNumericUpDown x:Name="MyNumericUpDown_PageNum" Width="120" Height="30"></z:MyNumericUpDown>
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF 使用自定义控件(custom control),资源字典(ResourceDictionary),用户控件(user control),及之间的对比 的相关文章

  • 命令绑定到 ContextMenu(在 ListBox 中的 ListBoxItem 上)不起作用[重复]

    这个问题在这里已经有答案了 在 WPF 中 借助 MVVM 光 有一个Class 由一些学生组成 以及Class持有一些Students 右键单击一个学生的名字 然后会显示一个MessageBox 这样就可以了 类详细信息视图 xaml
  • 应用程序启动时将焦点设置在 PasswordBox 上

    我无法将焦点设置在我的 PasswordBox 控件上是否有原因 C public Login InitializeComponent password Focus XAML
  • WPF 列表框 + 扩展器事件

    我在列表框的 ItemTemplate 中有一个 Expander 渲染得很好 我遇到的问题是 我希望在展开和 或选择扩展器时触发 ListBox SelectionChanged 事件 MouseDown 事件似乎没有冒泡到 ListBo
  • Visibility = IsCollapsed 是否跳过数据绑定部分?

    如果我将 StackPanel 或任何绑定区域设置为 折叠 数据会加载吗 它会触发它的 Loaded 事件吗 Yes 您的数据绑定将被评估 您的初始化事件将会触发 并且 您的 Loaded 事件将会触发 但在视觉树的部分中Visibilit
  • 我的 WPF 应用程序未触发 MainWindow_Loaded

    我目前正在关注Pluralsight C Fundamentals Part 1并在Classes and Objects视频部分指导我在 Visual Studio 中创建一个新的 WPF 应用程序并填写代码 这导致以下结果 namesp
  • 支持全方向动画的扩展器

    我的目标 是创建一个带有扩展动画的自定义扩展器 并且应该支持所有方向 我尝试过的 我在以下人员的帮助下实施了一个解决方案this http www codeproject com Articles 248112 Templating WPF
  • 当列表失去焦点时,WPF SelectedItem 颜色消失

    我有一个WPFWindow其中基本上有一个ListBox显示项目列表 然后我有一个ListView基本上显示的详细信息SelectedItem in the ListBox 问题是 当焦点不在ListBox突出显示的颜色消失了 我无法再看到
  • 使用自定义视觉效果创建无边框窗户

    我想使用 WPF 创建一个看起来不像常规窗口的自定义窗口 我想要创建的窗口类似于MacOs窗口 标题居中 带有阴影效果 控件按钮位于窗口左侧 我确实创建了一个无边框窗口 但我有一些问题 1 如何在 XAML 中设置最大化 最小化和关闭按钮的
  • 如何禁用箭头键更改焦点

    我有一个 WPF 窗口 其中有一些控件 按钮 组框等 和一个大控件Viewport3D在一个Border 视口显示 3D 场景 我希望使用箭头键来移动其相机 问题 方向键总是将焦点改变到另一个UIElement 如何通过箭头键禁用焦点更改并
  • 如何在 WPF 数据网格中添加页脚行?

    如何在 WPF 数据网格中添加页脚行 我必须在 WPF 数据网格中为每列的总和添加一行 我不想使用任何 dll 或 telerik 以及类似的东西 仅使用 Microsoft 组件来执行此操作 我正在尝试这样做
  • 打开和关闭 WPF DataGrid 背景图像?

    我有一个 DataGrid 当它为空时 我希望显示背景图像 当填充 DataGrid 时 我希望图像消失 并在再次清除 DataGrid 时重新出现 这可以通过 XAML 或 C 实现吗 if myDataGridView Rows Cou
  • WPF 中的图像变得模糊

    我正在使用 C 在 WPF 中开发应用程序 我将图像放入 WrapPanel 中 并在带有一个边框的网格内显示 并在按钮中使用图像 问题是我的图像控件失去了质量 我无法在这里发布我的图片 所以我只是在这里描述 I used SnapsToD
  • WPF - 按多列排序时使用自定义比较器

    我有一个 ListView GridView 我想按 2 列排序 因此如果第 1 列中有 2 个以上的项目具有相同的值 它将按第 2 列排序 非常简单 但是在对 A Z 进行排序时 空字符串会出现在顶部 我想把它们移到底部 我制作了一个比较
  • 可编辑的 WPF 列表框

    我有一个绑定到 WPF 中的 ListBox 的 ObservableCollection 我希望列表框可编辑 并将编辑更改保存到集合中 由于 WPF 不提供可编辑的列表框 因此我尝试通过更改 ListBox ItemTemplate 创建
  • 如何引用 dotNet Core 项目?

    我想将 dotNet Core 项目引用到 WPF 项目 我的 WPF 项目使用 v4 6 2 dotNet Framework 我的 dotNet Core 项目使用 v1 6 dotNet Standard 当我尝试引用它时 出现此错误
  • 当应用程序未聚焦时监听按键

    我有一个应用程序 C 4 0 WPF 它是隐藏的 可以通过单击系统托盘图标或我创建的其他框架 停靠在左侧和最上面的小框架 来显示 My customer wants to add a new way to display the appli
  • 如何使WPF TreeView风格成为WinForms TreeView?

    WPF 默认的 TreeView 非常好 我仍然希望它有连接每个子元素的线 就像 Windows 窗体 TreeView 一样 我在网上搜索了一些例子 但设计得不够好 我怎样才能用WPF实现它 让我回答我自己的问题 Code 您需要做的只是
  • Silverlight/WPF 按钮上的 MouseOver 样式

    努力为鼠标悬停的按钮设置样式 我已经成功地设置了按钮的样式 纯红色 但我希望每当鼠标悬停时它都会更改为纯黑色 我是 XAML 新手 我可以看到它需要某种类型的故事板 动画 不确定具体如何执行此操作 任何帮助将不胜感激 这与 WPF 和 Si
  • 获取列表框中视图中的项目

    我有一个 ListBox 其属性 VirtualizingStackPanel VirtualizationMode 设置为 回收 我正在绑定一个自定义集合 实现IList and IList
  • 一个好的 WPF 滚动时间线控件? (精美的日期时间选择器)

    我正在寻找可以用作时间线控件的东西 一种 横幅 用户可以向左或向右拖动以前进或后退 然后他或她应该能够在该控件上选择一个时间点 一个精美的日期时间选择器 有任何想法吗 欢迎您尝试我的新 TimelineControl 我已经在 codepl

随机推荐