Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TextboxHelper.ButtonCommand Binding using Caliburn

I am having a problem binding the TextboxHelper.ButtonCommand (from mahapps.metro) to my view model using caliburn.

At the moment I have this working using a delegate command.

View:

<TextBox Name="TextBoxContent"
             mui:TextboxHelper.ButtonContent="s"
             mui:TextboxHelper.ButtonCommand="{Binding DelCommand, Mode=OneWay}"
             Style="{DynamicResource ButtonCommandMuiTextBox}" />

ViewMode:

ICommand DelCommand
{
    get {return new Command();}
}

void Command() { //Handle press here }

However I really would like to use caliburn not the delegate command to acheive this. I have tried using the event triggers on the textbox to no avail, like so...

<TextBox Name="TextBoxContent" mui:TextboxHelper.ButtonContent="s"
             Style="{DynamicResource ButtonCommandMuiTextBox}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="mui:TextboxHelper.ButtonCommand">
                <i:EventTrigger.Actions>
                    <cal:ActionMessage MethodName="Command"/>
                </i:EventTrigger.Actions>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </TextBox>

Is there a reason why this can't be done?

Thanks

like image 767
Nick Williams Avatar asked Oct 02 '22 22:10

Nick Williams


2 Answers

I have created an attached property attaching the Caliburn Message to the MahApps TextBox button.

public static class MahappsHelper
{
    /// <summary>
    /// Attach Caliburn cal:Message.Attach for the Mahapps TextBoxHelper.Button
    /// </summary>
    public static readonly DependencyProperty ButtonMessageProperty =
        DependencyProperty.RegisterAttached("ButtonMessage", typeof(string), typeof(MahappsHelper), new PropertyMetadata(null, ButtonMessageChanged));

    public static string GetButtonMessage(DependencyObject obj)
    {
        return (string)obj.GetValue(ButtonMessageProperty);
    }

    public static void SetButtonMessage(DependencyObject obj, string value)
    {
        obj.SetValue(ButtonMessageProperty, value);
    }

    private static void ButtonMessageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement textBox = d as TextBox;
        if (d == null)
            textBox = d as PasswordBox;
        if (d == null)
            textBox = d as ComboBox;
        if (textBox == null)
            throw new ArgumentException("ButtonMessage does not work with control " + d.GetType());

        textBox.Loaded -= ButtonMessageTextBox_Loaded;

        Button button = GetTextBoxButton(textBox);
        if (button != null)
        {
            SetButtonMessage(textBox, button);
            return;
        }

        // cannot get button, try it in the Loaded event
        textBox.Loaded += ButtonMessageTextBox_Loaded;
    }

    private static Button GetTextBoxButton(FrameworkElement textBox)
    {
        return TreeHelper.FindChild<Button>(textBox, "PART_ClearText");
    }

    private static void ButtonMessageTextBox_Loaded(object sender, RoutedEventArgs e)
    {
        FrameworkElement textBox = (FrameworkElement)sender;
        textBox.Loaded -= ButtonMessageTextBox_Loaded;

        Button button = GetTextBoxButton(textBox);
        SetButtonMessage(textBox, button);
    }

    /// <summary>
    /// Set Caliburn Message to the TextBox button.
    /// </summary>
    private static void SetButtonMessage(FrameworkElement textBox, Button button)
    {
        if (button == null)
            return;

        string message = GetButtonMessage(textBox);
        Caliburn.Micro.Message.SetAttach(button, message);
    }
}

And usage:

    <TextBox x:Name="SearchBox" mahapps:TextBoxHelper.Watermark="Search ..."
             cal:Message.Attach="[KeyDown] = [Search(SearchBox.Text, $eventArgs)]"
             my:MahappsHelper.ButtonMessage="Search(SearchBox.Text)" />
like image 91
xmedeko Avatar answered Oct 21 '22 18:10

xmedeko


This is because it's not an event, you could solve this by turning the call to the command into an attached event then have caliburn watch that event instead.

I'll omit the attached event code, because it's lengthy but can be found here: Custom attached events in WPF

Something like

public class MyControlExtension
{
    public static readonly DependencyProperty SendMahAppsCommandAsEventProperty = DependencyProperty.RegisterAttached("SendMahAppsCommandAsEvent", typeof(bool), ... etc ... );

    public static SetSendMahAppsCommandAsEvent(DependencyObject element, bool value)
    {
        if (value) 
               TextboxHelper.SetButtonCommand(element, CreateCommand(element));
        else 
               TextboxHelper.SetButtonCommand(null);
    }

    public static bool GetHeaderSizingGroup(DependencyObject element)
    {
        return (bool) element.GetValue(SendMahAppsCommandAsEventProperty);
    }

    private static ICommand CreateCommand(DependencyObject element) 
    {
          return new MyCommandThatRaisesAttachedEvent(element);
    }
}
like image 1
Rhys Bevilaqua Avatar answered Oct 21 '22 18:10

Rhys Bevilaqua