Some text

MVVM: How to make a function call on a control?

In XAML, I have a TextBox with x: Name MyTextBox.

<TextBox x:Name="MyTextBox">Some text</TextBox>

For speed reasons, I want to call a method .AppendText, for example. In the C # code behind, I would callMyTextBox.AppendText("...")

However, this is not very similar to MVVM. If I want to make a function call on a control using binding to my ViewModel, what is an elegant way to achieve this?

I am using MVVM Light.

Update

I would use the answer from @XAML Lover if I wanted a simple and quick solution. This answer uses Blend behavior that is less than C #.

I would use the answer from @Chris Eelmaa if I wanted to write a reusable Dependency property that I could apply to any TextBox in the future. This example is based on Dependency, which, being a little more complex, very powerful and reusable once it is written. Since it connects to the field type, there is also slightly less XAML to use it.

+4
source share
2 answers

, , , , . ViewModel. - . DependencyProperty Action <string> , AppendText .

public class AppendTextBehavior : Behavior<TextBlock>
{
    public Action<string> AppendTextAction
    {
        get { return (Action<string>)GetValue(AppendTextActionProperty); }
        set { SetValue(AppendTextActionProperty, value); }
    }

    // Using a DependencyProperty as the backing store for AppendTextAction.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty AppendTextActionProperty =
        DependencyProperty.Register("AppendTextAction", typeof(Action<string>), typeof(AppendTextBehavior), new PropertyMetadata(null));

    protected override void OnAttached()
    {
        SetCurrentValue(AppendTextActionProperty, (Action<string>)AssociatedObject.AppendText);
        base.OnAttached();
    }
}

OnAttached , TextBlock, DP of Behavior. TextBlock .

    <TextBlock Text="Original String"
               VerticalAlignment="Top">
        <i:Interaction.Behaviors>
            <wpfApplication1:AppendTextBehavior AppendTextAction="{Binding AppendTextAction, Mode=OneWayToSource}" />
        </i:Interaction.Behaviors>
    </TextBlock>

, ViewModel . . , TextBlock. . , View ViewModel.

public class ViewModel
{
    public Action<string> AppendTextAction { get; set; }

    public ICommand ClickCommand { get; set; }

    public ViewModel()
    {
        ClickCommand = new DelegateCommand(OnClick);
    }

    private void OnClick()
    {
        AppendTextAction.Invoke(" test");
    }
}
+4

. AppendText , . MVVM , .

, ITextBuffer:

public interface ITextBuffer
{
    void Delete();
    void Delete(int offset, int length);

    void Append(string content);
    void Append(string content, int offset);

    string GetCurrentValue();

    event EventHandler<string> BufferAppendedHandler;
}

internal class MyTextBuffer : ITextBuffer
{
    #region Implementation of ITextBuffer

    private readonly StringBuilder _buffer = new StringBuilder();

    public void Delete()
    {
        _buffer.Clear();
    }

    public void Delete(int offset, int length)
    {
        _buffer.Remove(offset, length);
    }

    public void Append(string content)
    {
        _buffer.Append(content);

        var @event = BufferAppendedHandler;
        if (@event != null)
            @event(this, content);
    }

    public void Append(string content, int offset)
    {
        if (offset == _buffer.Length)
        {
            _buffer.Append(content);
        }
        else
        {
            _buffer.Insert(offset, content);
        }
    }

    public string GetCurrentValue()
    {
        return _buffer.ToString();
    }

    public event EventHandler<string> BufferAppendedHandler;

    #endregion
}

viewmodels. , , , , .

- :

public sealed class MvvmTextBox
{
    public static readonly DependencyProperty BufferProperty =
        DependencyProperty.RegisterAttached(
            "Buffer",
            typeof (ITextBuffer),
            typeof (MvvmTextBox),
            new UIPropertyMetadata(null, PropertyChangedCallback)
        );

    private static void PropertyChangedCallback(
        DependencyObject dependencyObject,
        DependencyPropertyChangedEventArgs depPropChangedEvArgs)
    {
        // todo: unrelease old buffer.
        var textBox = (TextBox) dependencyObject;
        var textBuffer = (ITextBuffer) depPropChangedEvArgs.NewValue;

        var detectChanges = true;

        textBox.Text = textBuffer.GetCurrentValue();
        textBuffer.BufferAppendedHandler += (sender, appendedText) =>
        {
            detectChanges = false;
            textBox.AppendText(appendedText);
            detectChanges = true;
        };

        // todo unrelease event handlers.
        textBox.TextChanged += (sender, args) =>
        {
            if (!detectChanges)
                return;

            foreach (var change in args.Changes)
            {
                if (change.AddedLength > 0)
                {
                    var addedContent = textBox.Text.Substring(
                        change.Offset, change.AddedLength);

                    textBuffer.Append(addedContent, change.Offset);
                }
                else
                {
                    textBuffer.Delete(change.Offset, change.RemovedLength);
                }
            }

            Debug.WriteLine(textBuffer.GetCurrentValue());
        };
    }

    public static void SetBuffer(UIElement element, Boolean value)
    {
        element.SetValue(BufferProperty, value);
    }
    public static ITextBuffer GetBuffer(UIElement element)
    {
        return (ITextBuffer)element.GetValue(BufferProperty);
    }
}

, StringBuilder ( :), TextBox.

, , - :

public class MyViewModel
{
    public ITextBuffer Description { get; set; }

    public MyViewModel()
    {
        Description= new MyTextBuffer();

        Description.Append("Just testing out.");
    }
}

:

<TextBox wpfApplication2:MvvmTextBox.Buffer="{Binding Description}" />
+1

Source: https://habr.com/ru/post/1570799/


All Articles