Click here to Skip to main content
15,867,568 members
Please Sign up or sign in to vote.
2.50/5 (2 votes)
See more:
Hello

I need to use a custom user control.

I use this XAML code :

C#
<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>


And behind CS :

C#
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);
 
        }
    }
 
 
}


C#
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>


And Behind CS on my application :

C#
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 :

C#
IsChecked="{Binding bChecked}"


To check all for example :

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


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.
Posted
Updated 2-Oct-17 3:57am
Comments
Bernhard Hiller 2-Oct-17 4:34am    
What do you expect to happen? And what does happen instead? I do not see any behavior related to that property.
Steve15f 2-Oct-17 4:40am    
Hello
In my C# User Control i have

public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}

I need to check / uncheck my button if bChecked is true or false

Thank you
johannesnestler 2-Oct-17 8:27am    
I think you question is confusing. "a custom user control"... "custom Control" and "user Control" are terms with a special meaning in WPF (just the first hit on Google for me: https://stackoverflow.com/questions/1322451/what-is-the-difference-between-user-control-custom-control-and-component ).

What you wanted: A customcontrol with a default (generic) theme (visual tree will be replaceable later)
What you created: A UserControl with code-behind (visual tree will not be replaceable later)

So I suggest to create a customcontrol out of your code and use TemplateBindings inside it's visual tree (the XAML) for things like your "Checked" state on the element that will represent that state inside your control's visual tree. If you don't know what I talk about (very likely - I'd guess you come from WinForms), better read some basics about WPF and controls in the documentation berfore you go any further with this... Rule of thumb: Never make CustomControls if you don't know your WPF in and out, and if you do, do it correctly (behaviors?)
Steve15f 2-Oct-17 8:32am    
Yes, sorry, i will say user control

My control work, but i need a property IsChecked too

Yes, i come from Winforms.

Can you give me more information ?

I created a DLL with my custom control. It's not correct ?

I created a project type library of user controle WPF and i insert my DLL on my project.

It's ok but i don't have the property checked
johannesnestler 2-Oct-17 9:08am    
No need for excuse ;) I just wanted to bring you in the right direction...you have to understand how dependencyproperties, Control theming, visual trees and so on work... this will prohibt such a mess for your next Control. So you will have to learn how to do things in WPF. Maybe my "rule of thumb" can be missunderstood... What I wanted to say - there is very seldom need for a "Control" in WPF like you were used from WinForms - because you maybe better work with MVVM pattern there... Things that can not be explained in a short QA-posting...

But I understand you want a quick soluton: I'd start here: I don't see you do anything with the IsChecked-Property inside your Code. so what Magic you expect to happen? In other words how is your Checked stated represented visually? Wait a Little I will try to create an example for you to understand the different approaches you could take here - maybe you can see a solution then...

1 solution

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));
}


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>



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

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:

<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:
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
 
Share this answer
 
Comments
Steve15f 2-Oct-17 10:18am    
Thank you very much.

I add in my project : a User Control WPF.

In this XAML :

<UserControl x:Class="Plutus.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:Plutus"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Background="White" Width="301">
<textblock> UserControl - a composition of existing Controls
<CheckBox x:Name="checkbox" Content="I represent the checked state">



In this Behind C# :

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));

Correct ?

In my project XAML :

<stackpanel>

<local:UserControl1 x:Name="usercontrol1">



<CheckBox x:Name="checkbox" Content="I'm cooler - using MVVM and let the WPF do the rest" IsChecked="{Binding IsChecked}">





In my behind c#

private void Button_Click(object sender, RoutedEventArgs e)
{
//UserControl.IsChecked = !UserControl1.IsChecked;
//customcontrol.IsChecked = !customcontrol.IsChecked;
//checkbox.IsChecked = !checkbox.IsChecked;

}
Correct ?

Thank you
johannesnestler 2-Oct-17 10:43am    
you can try all approaches at once just recreate the Project with all the files I showed...
Steve15f 2-Oct-17 10:46am    
Thank you. I tried.

But, it's not the result waited.

I have a checkbox, not a button.

Even, it's ok, i succeed to display every checkbox with my datacontext.

This code do not work :


private void Button_Click(object sender, RoutedEventArgs e)
{
usercontrol1.IsChecked = !usercontrol1.IsChecked;
customcontrol.IsChecked = !customcontrol.IsChecked;
checkbox.IsChecked = !checkbox.IsChecked;
}

the name usercontrol1 do not exist in the actual context

thank you !
Steve15f 3-Oct-17 4:03am    
Hello
An example.

I would this result :

http://nsa39.casimages.com/img/2017/10/03/171003103015495315.png

It's ok with my solution write in mmy first message

But, with your solution, i have this result :

http://nsa39.casimages.com/img/2017/10/03/171003103015578367.png

Thank you
johannesnestler 3-Oct-17 7:00am    
You realized i showed an example how to use Binding, TemplateBinding and DP, don't you? I didn't write your code for you - So just apply the idea to your solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900