Question

I just want to enable or disable the button inside a ControlTemplate for a WPF Editor that I'm using.

Was it helpful?

Solution

I agree with Joel that the preferred method would be to trigger the setting of the button's Enabled property with xaml markup, either through a trigger or by binding the Enabled value to another dependency property, possibly on a parent element, likely with the help of a ValueConverter.

However, if you have to do it explicitly in C#, you can use the FindName() method on the template property of the button. There's an MSDN 'how to' linked here.

OTHER TIPS

My I recommend that buttons are easily controled through RoutedUICommands - including easily enabling and disabling them. Commands do not need any type of reference to the Button so this solves your problem, too.

See here:

<Window.CommandBindings>
    <CommandBinding 
        Command="{x:Static local:MyCommands.MyCommand}"
        Executed="CommandBinding_Executed"
        CanExecute="CommandBinding_CanExecute" />
</Window.CommandBindings>

<Window.Resources>
    <ControlTemplate x:Key="MyTemplate" TargetType="Label">
        <Button Command="{x:Static local:MyCommands.MyCommand}">
            <TextBlock>
                Click Me
                <TextBlock Text="{TemplateBinding Content}" />
            </TextBlock>
        </Button>
    </ControlTemplate>
</Window.Resources>

<StackPanel>
    <Label Template="{StaticResource MyTemplate}">1</Label>
    <Label Template="{StaticResource MyTemplate}">2</Label>
    <Label Template="{StaticResource MyTemplate}">3</Label>
    <Label Template="{StaticResource MyTemplate}">4</Label>
    <Label Template="{StaticResource MyTemplate}">5</Label>
</StackPanel>

Use this:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void CommandBinding_CanExecute(object sender, System.Windows.Input.CanExecuteRoutedEventArgs e)
    {
        // your logic here
        int _Integer = -1;
        int.TryParse(e.Parameter.ToString(), out _Integer);
        e.CanExecute = _Integer % 2 == 0;
    }

    private void CommandBinding_Executed(object sender, System.Windows.Input.ExecutedRoutedEventArgs e)
    {
        // do something when clicked
    }
}

public static class MyCommands
{
    public static RoutedUICommand MyCommand = new RoutedUICommand();
}

Looks like:

screenshot

You really shouldn't be doing that explicitly, but instead be setting it with Triggers in the ControlTemplate itself. These Triggers would be reacting to some other change, and would set the Enabled property of the Button.

I had an issue with buttons in controlTemplates & dataTemplates. I find triggers are often too cumbersome to provide exactly what my clients want, I ended up with too many converters. The method I first tried was to define these more difficult templates inline so they could be bound to commands (& codebehind events) on my screens ViewModel.

if you are templating your own control, I should mention the easiest method is to simply name the button then use something like this:

hourHand   = this.Template.FindName( "PART_HourHand",   this ) as Rectangle;

Recently however, I've changed tact (back to indevidual files.. RE-USE!) but started adding a ViewModel (of sorts) which I suffix ...TemplateCommandStore to all my templates that get a bit complex. I even use this when templating my customcontrols (for consistency, mostly)

public class BookingDetailsTemplateCommandStore
{
    public OpenWindowCommand_Command OpenWindowCommand_Command { get; set; }

    public BookingDetailsTemplateCommandStore()
    {
        OpenWindowCommand_Command = new OpenWindowCommand_Command( this );
    }       
}

I can then happily use this command in a template. You can also pass control references into the command store by binding a (dependancy?) property to it to capture events & excise more precise control over your templates.

<DataTemplate DataType="{x:Type LeisureServices:BookingSummary}">
    <Border Height="50" otherStyling="xyz">
        <Border.Resources>
            <local:BookingDetailsTemplateCommandStore x:Key="CommandStore" />
        </Border.Resources>
        <DockPanel>
            <Button otherStyling="xyz"
                    Command="{Binding Source={StaticResource CommandStore},
                                      Path=OpenWindowCommand_Command}" />

MVVM: I find that so long as graphical logic is just that, and completely distinct from business logic, this methodology doesn't interfere with MVVM. In essence I add consistent C# code-ability to Templates, which anyone who spent too much time in winforms might miss as much as I do.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top