C#WPF自定义用户控件

编程入门 行业动态 更新时间:2024-10-26 09:35:14
本文介绍了C#WPF自定义用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

你好 我需要使用自定义用户控件。 我使用这个XAML代码:

Hello I need to use a custom user control. I use this XAML code :

<UserControl x:Class="WpfClickableImage.ControlClickableImage" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" Name="UC" xmlns:mc="schemas.openxmlformats/markup-compatibility/2006" xmlns:d="schemas.microsoft/expression/blend/2008" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300" > <StackPanel> <Button Click="Button_Click" Margin="10" HorizontalAlignment="Center" ToolTip="Click on Fred"> <Button.Template> <ControlTemplate> <Border x:Name="theBorder" BorderBrush="Transparent" BorderThickness="2"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Image Grid.Column="0" Source="{Binding ElementName=UC, Path=Image}" Width="{Binding ElementName=UC, Path=ImageWidth}" Height="{Binding ElementName=UC, Path=ImageHeight}"/> <StackPanel Grid.Column="1" Orientation="Vertical" Margin="5"> <TextBlock Text="{Binding ElementName=UC, Path=Text1}" Margin="10,0,0,0"/> <TextBlock Text="{Binding ElementName=UC, Path=Text2}" Margin="10,0,0,0"/> </StackPanel> </Grid> </Border> <ControlTemplate.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="BorderBrush" TargetName="theBorder" Value="LightSkyBlue"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Button.Template> </Button> </StackPanel> </UserControl>

CS背后:

And behind CS :

namespace WpfClickableImage { /// <summary> /// Logique d'interaction pour ControlClickableImage.xaml /// </summary> public partial class ControlClickableImage : UserControl { public ControlClickableImage() { InitializeComponent(); } public ImageSource Image { get { return (ImageSource)GetValue(ImageProperty); } set { SetValue(ImageProperty, value); } } // Using a DependencyProperty as the backing store for Image. This enables animation, styling, binding, etc... public static readonly DependencyProperty ImageProperty = DependencyProperty.Register("Image", typeof(ImageSource), typeof(ControlClickableImage), new UIPropertyMetadata(null)); public ImageSource ImageBack { get { return (ImageSource)GetValue(ImageBackProperty); } set { SetValue(ImageBackProperty, value); } } // Using a DependencyProperty as the backing store for ImageBack. This enables animation, styling, binding, etc... public static readonly DependencyProperty ImageBackProperty = DependencyProperty.Register("ImageBack", typeof(ImageSource), typeof(ControlClickableImage), new UIPropertyMetadata(null)); public double ImageWidth { get { return (double)GetValue(ImageWidthProperty); } set { SetValue(ImageWidthProperty, value); } } // Using a DependencyProperty as the backing store for ImageWidth. This enables animation, styling, binding, etc... public static readonly DependencyProperty ImageWidthProperty = DependencyProperty.Register("ImageWidth", typeof(double), typeof(ControlClickableImage), new UIPropertyMetadata(16d)); public double ImageHeight { get { return (double)GetValue(ImageHeightProperty); } set { SetValue(ImageHeightProperty, value); } } // Using a DependencyProperty as the backing store for ImageHeight. This enables animation, styling, binding, etc... public static readonly DependencyProperty ImageHeightProperty = DependencyProperty.Register("ImageHeight", typeof(double), typeof(ControlClickableImage), new UIPropertyMetadata(16d)); public string Text1 { get { return (string)GetValue(Text1Property); } set { SetValue(Text1Property, value); } } // Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... public static readonly DependencyProperty Text1Property = DependencyProperty.Register("Text1", typeof(string), typeof(ControlClickableImage), new UIPropertyMetadata("")); public string Text2 { get { return (string)GetValue(Text2Property); } set { SetValue(Text2Property, value); } } // Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... public static readonly DependencyProperty Text2Property = DependencyProperty.Register("Text2", typeof(string), typeof(ControlClickableImage), new UIPropertyMetadata("")); public bool IsChecked { get { return (bool)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); } } // Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(ControlClickableImage), new UIPropertyMetadata(false)); private void Button_Click(object sender, RoutedEventArgs e) { this.IsChecked = !IsChecked; // swap images ImageSource temp = this.Image; this.Image = this.ImageBack; this.ImageBack = temp; //les 2 events sont declenches ici if (this.IsChecked) OnCheckedChanged(this, e); else if (!this.IsChecked ) OnUnCheckChanged(this, e); } // event perso Checked public static readonly RoutedEvent CheckedEvent = EventManager.RegisterRoutedEvent( "Checked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ControlClickableImage)); // Provide CLR accessors for the event public event RoutedEventHandler Checked { add { AddHandler(CheckedEvent, value); } remove { RemoveHandler(CheckedEvent, value); } } // event perso UnChecked public static readonly RoutedEvent UnCheckedEvent = EventManager.RegisterRoutedEvent( "UnChecked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ControlClickableImage)); // Provide CLR accessors for the event public event RoutedEventHandler UnChecked { add { AddHandler(UnCheckedEvent, value); } remove { RemoveHandler(UnCheckedEvent, value); } } // methods charge de raiser les 2 events private void OnCheckedChanged(ControlClickableImage controlClickableImage, RoutedEventArgs e) { RoutedEventArgs newEventArgs = new RoutedEventArgs( ControlClickableImage.CheckedEvent); newEventArgs.Source = controlClickableImage; RaiseEvent(newEventArgs); } private void OnUnCheckChanged(ControlClickableImage controlClickableImage, RoutedEventArgs e) { RoutedEventArgs newEventArgs = new RoutedEventArgs(ControlClickableImage.UnCheckedEvent); newEventArgs.Source = controlClickableImage; RaiseEvent(newEventArgs); } } }

In my application : <Window x:Class="WpfClickableImage.Window1" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" xmlns:my="clr-namespace:WpfClickableImage" Title="Window1" Height="300" Width="300"> <StackPanel> <my:ControlClickableImage x:Name="yourcontrol" Image="calendar.png" ImageBack="worldwallpaper.jpg" Text1="ControlImageClickable" Text2="Description" HorizontalAlignment="Left" VerticalAlignment="Top" ImageWidth="20" ImageHeight="20" Margin="10" Checked="ControlClickableImage_Checked" UnChecked="ControlClickableImage_UnChecked"> </my:ControlClickableImage> </StackPanel> </Window>

和CS背后我的申请:

And Behind CS on my application :

namespace WpfClickableImage { /// <summary> /// Logique d'interaction pour Window1.xaml /// </summary> public partial class Window1 : Window { public Window1() { InitializeComponent(); } private void ControlClickableImage_Checked(object sender, RoutedEventArgs e) { ControlClickableImage ctl = e.Source as ControlClickableImage; MessageBox.Show(ctl.IsChecked.ToString() + " ; " + ctl.Text1 + " ; " + ctl.Text2); } private void ControlClickableImage_UnChecked(object sender, RoutedEventArgs e) { ControlClickableImage ctl = e.Source as ControlClickableImage; MessageBox.Show(ctl.IsChecked.ToString() + " ; " + ctl.Text1 + " ; " + ctl.Text2); } } }

这是工作。 但是,之前,在我的复选框上,我发送此绑定:

It's work. But, before, on my checkbox, i send this Binding :

IsChecked="{Binding bChecked}"

b $ b 要检查所有例子:

To check all for example :

private void btnTous_Click(object sender, RoutedEventArgs e) { foreach (var item in LstIlots) { item.bChecked = true; } }

但是这个属性IsChecked在我的用户控件中不起作用。 如何启用此参数? 谢谢。 我尝试过: 我尝试添加此IsChecked Binding bChecked in my XAML Application code:

But this property IsChecked don't work in my user control. How i can enable this parameter ? Thank you. What I have tried: I try to add this IsChecked Binding bChecked in my XAML Application code :

<my:ControlClickableImage x:Name="yourcontrol" Image="calendar.png" ImageBack="worldwallpaper.jpg" Text1="ControlImageClickable" Text2="Description" HorizontalAlignment="Left" VerticalAlignment="Top" ImageWidth="20" ImageHeight="20" Margin="10" Checked="ControlClickableImage_Checked" UnChecked="ControlClickableImage_UnChecked" IsChecked="{Binding bChecked}> </my:ControlClickableImage>

但它不是工作。 提前谢谢。

But it's not work. Thank you in advance.

推荐答案

史蒂夫, 我回到了承诺的例子:它显示了3种不同的方法(这里可能有第4种行为,但我不知道我想混淆你;) 我建议把它放在一个新的WPF应用程序Project中让它运行: 首先你需要一个CustomControl: Hi Steve, I'm back with the promised example: It Shows 3 different approaches (a 4th would be possible here with behaviors, but I don't want to confuse you ;) I suggest put this in a new WPF application Project and let it run: first you need a CustomControl: public class CustomControl : Control { static CustomControl() { DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomControl), new FrameworkPropertyMetadata(typeof(CustomControl))); } public bool IsChecked { get { return (bool)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); } } // Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(CustomControl), new PropertyMetadata(false)); }

和generic.xaml(该文件应在名为Themes的文件夹中生成如果你将一个自定义控件添加到WPF项目中。

and in generic.xaml (the file should be generated inside a Folder named "Themes" if you add a customcontrol to a WPF Project).

esourceDictionary xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp4"> <Style TargetType="{x:Type local:CustomControl}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:CustomControl}"> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <StackPanel> <TextBlock> UserControl - a composition of existing Controls</TextBlock> <CheckBox Content="I represent the checked state" IsChecked="{TemplateBinding IsChecked}"></CheckBox> </StackPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>

秒一个UserControl:

second a UserControl:

<UserControl x:Class="WpfApp4.UserControl1" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" xmlns:mc="schemas.openxmlformats/markup-compatibility/2006" xmlns:d="schemas.microsoft/expression/blend/2008" xmlns:local="clr-namespace:WpfApp4" mc:Ignorable="d"> <StackPanel Background="White" Width="301"> <TextBlock> UserControl - a composition of existing Controls</TextBlock> <CheckBox x:Name="checkbox" Content="I represent the checked state"></CheckBox> </StackPanel> </UserControl>

public partial class UserControl1 : UserControl { public bool IsChecked { get { return (bool)GetValue(IsCheckedProperty); } set { SetValue(IsCheckedProperty, value); checkbox.IsChecked = value; } } // Using a DependencyProperty as the backing store for IsChecked. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(UserControl1), new PropertyMetadata(false)); public UserControl1() { InitializeComponent(); } }

third a ViewModel

third a ViewModel

public class ViewModel : INotifyPropertyChanged { bool m_bIsChecked; // backing field for property IsChecked public event PropertyChangedEventHandler PropertyChanged; public bool IsChecked { get { return m_bIsChecked; } set { if (m_bIsChecked != value) { m_bIsChecked = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsChecked))); // this is just for example, don't raise event directly from code, always create a dedicated OnXXX method to just raise the event } } } }

and a test-window (I used pre-generated MainWindow) to Show the use:

and a test-window (I used pre-generated MainWindow) to Show the use:

<Window x:Class="WpfApp4.MainWindow" xmlns="schemas.microsoft/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft/winfx/2006/xaml" xmlns:d="schemas.microsoft/expression/blend/2008" xmlns:mc="schemas.openxmlformats/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp4" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <StackPanel> <local:UserControl1 x:Name="usercontrol1"> </local:UserControl1> <local:CustomControl x:Name="customcontrol"> </local:CustomControl> <CheckBox x:Name="checkbox" Content="I'm cooler - using MVVM and let the WPF do the rest" IsChecked="{Binding IsChecked}"></CheckBox> <Button Content="Set checked state by code" Click="Button_Click"> </Button> </StackPanel> </Window>

with Code behind:

with Code behind:

public partial class MainWindow : Window { ViewModel m_viewmodel = new ViewModel(); public MainWindow() { InitializeComponent(); DataContext = m_viewmodel; } private void Button_Click(object sender, RoutedEventArgs e) { usercontrol1.IsChecked = !usercontrol1.IsChecked; customcontrol.IsChecked = !customcontrol.IsChecked; checkbox.IsChecked = !checkbox.IsChecked; } }

So what we see here: 1. a UserControl is just a bunch of other Controls + some DependencyProperties - nothing is done with binding (because you don’t Control the DataContext) 2. a CustomControl with a generic theme and TemplateBinding - better for your case I’d say. 3. Don’t create any controls use a pattern to bind data - MVVM - we just set the ViewModel as DataContext for the window and let the binding-mechanism do the rest. I would always go for approach 3 nowadays, sometimes you will still need approach 2, Approach 1 - as you found out for yourself is \"not so good\", because it’s not so easys to make it right without a lot of knowledge of WPF (same is true for Approach 2). I hope this helps you to find your current Problem. Kind regards Johannes

So what we see here: 1. a UserControl is just a bunch of other Controls + some DependencyProperties - nothing is done with binding (because you don't Control the DataContext) 2. a CustomControl with a generic theme and TemplateBinding - better for your case I'd say. 3. Don't create any controls use a pattern to bind data - MVVM - we just set the ViewModel as DataContext for the window and let the binding-mechanism do the rest. I would always go for approach 3 nowadays, sometimes you will still need approach 2, Approach 1 - as you found out for yourself is "not so good", because it's not so easys to make it right without a lot of knowledge of WPF (same is true for Approach 2). I hope this helps you to find your current Problem. Kind regards Johannes

更多推荐

C#WPF自定义用户控件

本文发布于:2023-11-11 17:53:16,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1579150.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   控件   用户   WPF

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!