Я все таки написал свой костыль, который работает вполне не плохо, но не идеально. Сейчас я все вкратце расскажу...
Начнем со вспомоготельного класса для вызова комманд:
public class ActionCommand : ICommand
{
private Action _action;
private Action<object> _actionObj;
public ActionCommand(Action action)
{
_action = action;
}
public ActionCommand(Action<object> actionObj)
{
_actionObj = actionObj;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
if (parameter == null)
{
_action?.Invoke();
}
else if (parameter is System.Windows.Controls.TextBox)
{
_actionObj?.Invoke(parameter);
}
}
public event EventHandler CanExecuteChanged;
}
Думаю тут ничего не стоит объяснять. Описаний подобных классов хватает. Я лишь добавил Action с параметром и проверку параметра на null и тип необходимого мне объекта.
Идем дальше...
Нужно к тэгу Window дописать следущий параметр и добавить соответствующую библиотеку, которая есть в nuget
xmlns:intr="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
Далее создадим наш контрол:
<TextBox Text="{Binding Log, Mode=OneWay}" IsReadOnly="True" Margin="5" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<intr:Interaction.Triggers>
<intr:EventTrigger EventName="TextChanged">
<intr:InvokeCommandAction Command="{Binding command_InitializedTextBox}"
CommandParameter="{Binding RelativeSource=
{RelativeSource
Mode=FindAncestor,
AncestorType=TextBox}}"/>
</intr:EventTrigger>
</intr:Interaction.Triggers>
</TextBox>
Обращаю внимание на
AncestorType=TextBox
. Вам необходимо поменять значение на необходимое вам(как и во вспомогательном классе), а иначе передастся найденный TextBox, если он вообще есть. Отвечаю сразу на ожидаемые вопросы:
использовать событие Loaded и Initialized не получится в данном случае, т.к. VM объявляется позже, чем срабатывают эти события.
Ну и идем к скоплению костылей... Во ViewModel
public ICommand command_InitializedTextBox
{
get
{
return new ActionCommand((object sender) => { InitializedTextBox(sender); });
}
}
private void InitializedTextBox(object sender)
{
_LogControl = ((System.Windows.Controls.TextBox)sender);
}
Тут должно быть все понятно.
А вот void для добавления текста.
private void AppendLogText(string getter)
{
if (_LogControl != null)
{
_LogControl.AppendText(getter);
}
else
{
Log += getter;
}
}
Текст изменяется биндингом только 1 раз.
Хочу отметить, что использовать данное решение стоит когда используются большие текста. ТекстБокс долго "думает" при использовании больших текстов и биндинга, а при использовании AppendText - нет.