Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to Bind to a Custom Controls Button Visibility from Within Another Control

Tags:

c#

mvvm

wpf

I have a custom control, which has a button:

<UserControl x:Class="Gambit.Views.FileSelectionControl"
    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" 
    SnapsToDevicePixels="True" 
    mc:Ignorable="d">
    ...
    <Button Content="Load" 
            Margin="5,5,5,5" 
            Height="22" 
            Width="70" 
            IsDefault="True" 
            IsEnabled="{Binding SelectedFileExists}" 
            AttachedCommand:CommandBehavior.Event="Click" 
            AttachedCommand:CommandBehavior.Command="{Binding CloseDialogCommand}"/>
    ...
</UserControl>

I want to include this control, in another control, but I want to set the Load buttons visibility at design time in the host control; something like

<UserControl x:Class="Gambit.Views.SomeOtherControl"
    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" 
    SnapsToDevicePixels="True" 
    mc:Ignorable="d">
    ...
    <GroupBox Header="Select Test Data">
        <Views:FileSelectionControl <Here Set the Load Button Visibility>/>
    </GroupBox>
    ...
</UserControl>

where <Here Set the Load Button Visibility> shows where i want to set the visibility of the control. How is this done [without breaking the MVVM pattern]?

Thanks for your time.

like image 632
MoonKnight Avatar asked Jan 04 '14 19:01

MoonKnight


3 Answers

You can create DependencyProperty in your UserControl:

public partial class SomeView : UserControl
{
    ...

    public static DependencyProperty ButtonVisibilityProperty = DependencyProperty.Register("ButtonVisibility", typeof(Visibility), typeof(SomeView));

    public Visibility ButtonVisibility
    {
        get { return (Visibility)GetValue(ButtonVisibilityProperty); }
        set { SetValue(ButtonVisibilityProperty, value); }
    }
}

bind it to Button.Visibility:

<UserControl x:Class="WpfApplication2.SomeView"
             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" 
             mc:Ignorable="d">
    <Button Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=ButtonVisibility}" Content="My Button"/>
</UserControl>

and then you can control Visibility from outside like so:

<local:SomeView ButtonVisibility="Collapsed"/>

and because it's a DependencyProperty you can use Binding as well

like image 142
dkozl Avatar answered Oct 17 '22 13:10

dkozl


Hi just create a bool or Visibility Type property in UserControl1 and set it in Usercontrol2 like

UserControl1 xaml

<UserControl x:Class="WpfApplication4.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" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <Button x:Name="Loadbutton" Content="load"/>
</Grid>

xaml.cs

 public UserControl1()
    {
        InitializeComponent();
    }

    bool showLoadButton;
    public bool ShowLoadButton
    {
        get { return showLoadButton; }
        set
        {
            showLoadButton = value;
            if (showLoadButton)
                Loadbutton.Visibility = Visibility.Visible;
            else
                Loadbutton.Visibility = Visibility.Collapsed;
        }

    }

UserControl2 Set ShowLoadButton True or false

<UserControl x:Class="WpfApplication4.UserControl2"
         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:WpfApplication4"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <local:UserControl1 ShowLoadButton="True"/>
</Grid>

like image 27
yo chauhan Avatar answered Oct 17 '22 15:10

yo chauhan


If you do not want to define a property in the UserControl, which you can always create attached dependency property, and you can declare it in a separate class under the common namespace.

Something like this:

MainWindow.xaml

<local:TestUserControl AttachedProperties:ButtonExt.Visibility="Visible" />

TestUserControl.xaml

<Button Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, 
                             Path=(AttachedProperties:ButtonExt.Visibility)}"
        Content="TestButton" />

Attached property definition:

public static class ButtonExt
{
    public static readonly DependencyProperty VisibilityProperty;

    public static void SetVisibility(DependencyObject DepObject, Visibility value)
    {
        DepObject.SetValue(VisibilityProperty, value);
    }

    public static Visibility GetVisibility(DependencyObject DepObject)
    {
        return (Visibility)DepObject.GetValue(VisibilityProperty);
    }

    static ButtonExt()
    {
        PropertyMetadata VisibiltyPropertyMetadata = new PropertyMetadata(Visibility.Collapsed);

        VisibilityProperty = DependencyProperty.RegisterAttached("Visibility",
                                                            typeof(Visibility),
                                                            typeof(ButtonExt),
                                                            VisibiltyPropertyMetadata);
    }
}

Some notes about code-behind in MVVM

I agree with @dkozl, his example does not violate the principle of MVVM, in some cases, the code is present in the View, for example (personally, I always try to avoid code-behind):

  • Installation DataContext.

  • The use of different patterns such as Mediator, Proxy, etc.

  • Determination of properties and behaviors that pertain only to View (as in your case).

The most important thing when you use the code-behind, it is that all actions possible through ViewModel occurred, ie in ViewModel contains all the logic and for example, in the View click event, call the function, which is in ViewModel.

For more information about code-behind, please see the answers to the recent question:

WPF MVVM Code Behind

like image 1
Anatoliy Nikolaev Avatar answered Oct 17 '22 15:10

Anatoliy Nikolaev