本文介绍了C#WPF自定义用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 29岁程序员,3月因学历无情被辞! 你好 我需要使用自定义用户控件。 我使用这个XAML代码:HelloI need to use a custom user control.I use this XAML code :<UserControl x:Class="WpfClickableImage.ControlClickableImage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="UC" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/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="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/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="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/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="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: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 ViewModelthird a ViewModelpublic 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="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: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 JohannesSo 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 regardsJohannes 这篇关于C#WPF自定义用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
06-21 09:00