Binding для события
Вот мой DialogHost
<MaterialDesign:DialogHost Identifier="RenameDialog" Style="{StaticResource MaterialDesignEmbeddedDialogHost}" Panel.ZIndex="2002" DialogMargin="0" Grid.ColumnSpan="3" Grid.RowSpan="2" Focusable="False" IsManipulationEnabled="True" FocusVisualStyle="{x:Null}">
<MaterialDesign:DialogHost.DialogContentTemplate>
<DataTemplate>
<Grid Height="150" Width="300" FocusVisualStyle="{x:Null}" >
<MaterialDesign:ColorZone Content="{Binding Header}" Height="50" Mode="PrimaryLight" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
<TextBox Text="{Binding Text, Mode=OneTime}" Margin="15 50 15 0" VerticalAlignment="Top" Style="{StaticResource MaterialDesignFloatingHintTextBox}"></TextBox>
<Button x:Name="Dialog3" Style="{StaticResource MaterialDesignFlatButton}" Content="Отмена" Margin="0 0 67 8" VerticalAlignment="Bottom" HorizontalAlignment="Right" FocusVisualStyle="{x:Null}" Command="MaterialDesign:DialogHost.CloseDialogCommand" CommandParameter="Cancel" />
<Button x:Name="Dialog4" Style="{StaticResource MaterialDesignFlatButton}" Content="OK" Margin="0 0 8 8" VerticalAlignment="Bottom" HorizontalAlignment="Right" FocusVisualStyle="{x:Null}" Command="MaterialDesign:DialogHost.CloseDialogCommand" CommandParameter="OK" />
</Grid>
</DataTemplate>
</MaterialDesign:DialogHost.DialogContentTemplate>
</MaterialDesign:DialogHost>
Вот-так я его вызываю:
DialogHost.Show(new { Header = "Header", Text = "Text" }, "RenameDialog");
Как сделать так чтобы, я мог третим параметром указывать обработчик TextChanged для TextBox?
Что-то типа такого
void TextBox_TextChanged(object NameTablesender, TextChangedEventArgs e)
{
}
DialogHost.Show(new { Header = "Header", Text = "Text", Changer = TextBox_TextChanged}, "RenameDialog");
Ответы (1 шт):
Давайте я покажу вам код, который имел в виду @aepot.
Вам нужно определить аргумент так:
class DialogArgs : VM
{
public DialogArgs(Action<string> textChangeCallback) =>
this.textChangeCallback = textChangeCallback ??
throw new ArgumentNullException(nameof(textChangeCallback));
string header;
public string Header
{
get => header;
set => Set(ref header, value);
}
string text;
public string Text
{
get => text;
set
{
if (Set(ref text, value))
textChangeCallback(text);
}
}
private readonly Action<string> textChangeCallback;
}
Базовый класс VM с реализацией INotifyPropertyChanged вам пригодится и в других местах:
class VM : INotifyPropertyChanged
{
protected bool Set<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
RaisePropertyChanged(propertyName);
return true;
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged;
}
а вместо Text="{Binding Text, Mode=OneTime}" написать Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"
Ну и показ диалога при этом будет выглядеть так:
DialogHost.Show(
new DialogArgs(callback) { Header = "Header", Text = "Text" },
"RenameDialog");
(например, я пробовал вместо callback написать t => Debug.WriteLine(t), так что изменённый текст выводился в окошко Output).
Дополнение по результатам обсуждения в комментариях. Чтобы показывать ошибочный или неошибочный выбор имени, вам нужно добавить ещё пару свойств в DialogArgs:
bool isGood;
public bool IsGood
{
get => isGood;
set => Set(ref isGood, value);
}
string errorText;
public string ErrorText
{
get => errorText;
set => Set(ref errorText, value);
}
В вашем диалоге вы привязываете цвета к IsGood через конвертер (или пользуетесь триггером), и выводите текст из ErrorText в качестве сообщения об ошибке. А код вашего callback'а должен проверять имя, и устанавливать IsGood и ErrorText.
Например, так. Вот конвертер:
class HintColorConverter : IValueConverter
{
public object Convert(object value, Type t, object parameter, CultureInfo ci) =>
value is true ? Brushes.Black : Brushes.Red;
public object ConvertBack(object value, Type t, object parameter, CultureInfo ci) =>
throw new NotSupportedException();
}
Textbox в коде диалога:
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" Margin="15 50 15 0" VerticalAlignment="Top"
Style="{StaticResource MaterialDesignFloatingHintTextBox}"
Foreground="{Binding IsGood, Converter={StaticResource HintColorConverter}}"
materialDesign:HintAssist.Foreground="{Binding IsGood, Converter={StaticResource HintColorConverter}}"
materialDesign:TextFieldAssist.UnderlineBrush="{Binding IsGood, Converter={StaticResource HintColorConverter}}">
и в начала DataTemplate, конечно,
<DataTemplate.Resources>
<local:HintColorConverter x:Key="HintColorConverter"/>
</DataTemplate.Resources>
Вот такое хитрое создание DialogArgs (считаем чётную длину правильной):
DialogArgs args = null;
args = new DialogArgs(t => args.IsGood = t.Length % 2 == 0) { Header = "Header" };
args.Text = "Text";
await DialogHost.Show(args, "RenameDialog");
Результат:
Можно и через триггеры, тогда вам не нужен конвертер:
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" Margin="15 50 15 0" VerticalAlignment="Top">
<TextBox.Style>
<Style BasedOn="{StaticResource MaterialDesignFloatingHintTextBox}" TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsGood}">
<DataTrigger.Value><sys:Boolean>False</sys:Boolean></DataTrigger.Value>
<DataTrigger.Setters>
<Setter Property="Foreground" Value="Red"/>
<Setter Property="materialDesign:HintAssist.Foreground" Value="Red"/>
<Setter Property="materialDesign:TextFieldAssist.UnderlineBrush" Value="Red"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
(не забудьте где-то вверху xmlns:sys="clr-namespace:System;assembly=mscorlib")
Если проверка длинная, сделайте её асинхронной.
