简体   繁体   中英

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

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.

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

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>

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM