C#WPF自定义用户控件 [英] C# WPF custom user control

查看:74
本文介绍了C#WPF自定义用户控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好



我需要使用自定义用户控件。



我使用这个XAML代码:



Hello

I 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}"

< br $> 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 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="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



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自定义用户控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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