2
votes

I'm doing an WPF UserControl.

Inside of this UserControl, I've several Button that can be used on certains conditions, so binding them to a command is perfect.

The command called by those Buttons should not be available outside of the UserControl.

If I make my Commands private, the XAML of the UserControl says that he wants public member.

So, what is the way to go to have one UserControl that has several commands internally, but not available outside of the UserControl?

Example:

<Wizard CanGoPrevious="{Binding SomeViewModelProperty}">
    <WizardPage>
        <TextBlock>Page one</TextBlock>
    </WizardPage>
</Wizard>

Wizard's XAML:

<DockPanel DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type wizard:Wizard}}}" LastChildFill="True">
    <StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Right"> 
        <Button Content="{Binding PreviousButtonText}" Command="{Binding GoToPreviousPageCommand}"/>
    </StackPanel>
    <ContentControl ></ContentControl>
</DockPanel>

Wizard's Code behind:

//Protected doesn't work. Also, this command should not be available outside of the Wizard `UserControl`
protected DelegateCommand GoToPreviousPageCommand { get; set; } 

Which is assigned like this in the constructor

GoToPreviousPageCommand = new DelegateCommand(GoToPreviousPage, CanGoToPreviousPage);


    private void GoToPreviousPage()
    {
        //[...]
    }

    private bool CanGoToNextPage()
    {
        //Some usage of the Wizard's DP:
        return CanGoPrevious //&& some other stuff
    }
1
Don't bother. It's a user control--it's perfectly fine to include logic pertaining to the UI in the codebehind.user1228
@Will Ok, but it's not find to provide an UserControl with public access to commands that have to be available internally only.J4N

1 Answers

1
votes

EDIT : adding sample code (should be able to copy/past/run): Leave command as public, but make your ViewModel internal will make the command invisible to the outside code!

<Window x:Class="InternalCommandUsageSample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:InternalCommandUsageSample"
    Title="MainWindow" Height="350" Width="525">
<local:MyUserControl/>

code behind the window that tests user control:

using System.Windows;

namespace InternalCommandUsageSample
{
public partial class MainWindow : Window
{
    public MainWindow()
    {
        var vm = new MyViewModel();
        DataContext = vm;

        InitializeComponent();
    }
}

}

user control:

<UserControl x:Class="InternalCommandUsageSample.MyUserControl"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
    <TextBlock Text="{Binding Message, Mode=OneWay}"/>
    <Button Content="Test Me" Command="{Binding TestMeCommand}"/>
</StackPanel>

and the internal view model that is not visible outside your assembly:

internal class MyViewModel : INotifyPropertyChanged
{
    private string _message = "click the button";
    private DelegateCommand _cmd;

    public DelegateCommand TestMeCommand
    {
        get
        {
            return _cmd ?? (_cmd = new DelegateCommand(cmd => { Message = "Your button click envoked an internal command"; }));
        }
    }

    public string Message
    {
        get { return _message; }
        set
        {
            if (_message != value)
            {
                _message = value;
                OnPropertyChanged("Message");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

EDIT: addtional question was asked in comments on how to use dependency property of the suer control and a view model. There are many ways, this is one of them:

        public string MySampleDependencyProperty
    {
        get { return (string)GetValue(MySampleDependencyPropertyProperty); }
        set { SetValue(MySampleDependencyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MySampleDependencyPropertyProperty = 
        DependencyProperty.Register("MySampleDependencyProperty", typeof(string), 
        typeof(MyUserControl),
        new FrameworkPropertyMetadata("", 
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (o, e) => ((MyUserControl)o).OnMySampleDependencyPropertyChanged()));

    private void OnMySampleDependencyPropertyChanged()
    {
        viewMdoel.WhateverProperty = MySampleDependencyProperty;
    }