Привет, у меня есть приложение на Мауи, использующее ContentTemplates, где я пытаюсь связать событие Unfocused редактора с RelayCommand в модели представления.
Мне удалось привязать нажатие кнопки к RelayCommand, но команда Editor Unfocused не сработала.
К вашему сведению, я реализовал следующее решение, чтобы решить проблему, при которой редакторы не отвлекаются от нажатия за пределами элемента управления:
https://github.com/dotnet/maui/issues/21053
Пример репозитория здесь, где эта функциональность находится в MainPage:
Репо
Любая помощь очень ценится.
При работе с ContentView
лучше всего сосредоточиться на командах или свойствах. Если вы хотите сопоставить событие с командой, потребуется дополнительная работа, но это выполнимо. Однако, поскольку Editor
имеет свойство IsFocused
, мы можем объявить BindableProperty
, вызываемое IsEditorFocused
, и использовать OneWayBindingToSource
для распространения этого события от Editor
через ContentView
к Page
.
<!-- CustomEditor.xaml -->
<ContentView
x:Class = "Maui.StackOverflow.CustomEditor"
xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml">
<ContentView.ControlTemplate>
<ControlTemplate>
<Border>
<Editor IsFocused = "{TemplateBinding IsEditorFocused, Mode=OneWayToSource}" Placeholder = "CustomEntry" />
</Border>
</ControlTemplate>
</ContentView.ControlTemplate>
</ContentView>
// CustomEditor.xaml.cs
namespace Maui.StackOverflow;
public partial class CustomEditor : ContentView
{
public static readonly BindableProperty IsEditorFocusedProperty = BindableProperty.Create(nameof(IsEditorFocused), typeof(bool), typeof(CustomEditor), false);
public bool IsEditorFocused
{
get => (bool)GetValue(IsFocusedProperty);
set => SetValue(IsFocusedProperty, value);
}
public CustomEditor()
{
InitializeComponent();
}
}
И мы можем использовать его на нашей странице следующим образом:
<!-- EditorPage.xaml -->
<?xml version = "1.0" encoding = "utf-8" ?>
<ContentPage
x:Class = "Maui.StackOverflow.EditorPage"
xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local = "clr-namespace:Maui.StackOverflow"
x:Name = "thisPage"
Title = "EditorPage"
x:DataType = "local:EditorPage">
<VerticalStackLayout>
<Entry Placeholder = "Entry1" />
<local:CustomEditor IsEditorFocused = "{Binding IsEditorFocused, Mode=OneWayToSource, Source = {Reference thisPage}}" />
<Entry Placeholder = "Entry2" />
</VerticalStackLayout>
</ContentPage>
// EditorPage.xaml.cs
using System.Diagnostics;
namespace Maui.StackOverflow;
public partial class EditorPage : ContentPage
{
public static readonly BindableProperty IsEditorFocusedProperty = BindableProperty.Create(nameof(IsEditorFocused), typeof(bool), typeof(EditorPage), false);
public bool IsEditorFocused
{
get => (bool)GetValue(IsEditorFocusedProperty);
set => SetValue(IsEditorFocusedProperty, value);
}
public EditorPage()
{
InitializeComponent();
BindingContext = this;
PropertyChanged += (s, e) =>
{
switch (e.PropertyName)
{
case nameof(IsEditorFocused):
Debug.WriteLine($"IsEditorFocused changed to {IsEditorFocused}");
break;
}
};
}
}
Я упомянул, что можно преобразовать события в команды. Я следую шаблону: я объявляю тонкую оболочку для того, для чего мне нужны команды. В этом случае я объявлю CustomEditorInner
, который по сути является оберткой Editor
, где события Focused и Unfocused преобразуются в ICommands
. Затем я могу переписать CustomEditor
и свой ContentPage
, чтобы использовать их. На ContentPage
я объявляю RelayCommand
.
// CustomEditorInner.cs
using System.Windows.Input;
namespace Maui.StackOverflow;
class CustomEditorInner : Editor
{
public static readonly BindableProperty FocusedCommandProperty = BindableProperty.Create(nameof(FocusedCommand), typeof(ICommand), typeof(CustomEditorInner), null);
public ICommand FocusedCommand
{
get => (ICommand)GetValue(FocusedCommandProperty);
set => SetValue(FocusedCommandProperty, value);
}
public static readonly BindableProperty UnfocusedCommandProperty = BindableProperty.Create(nameof(UnfocusedCommand), typeof(ICommand), typeof(CustomEditorInner), null);
public ICommand UnfocusedCommand
{
get => (ICommand)GetValue(UnfocusedCommandProperty);
set => SetValue(UnfocusedCommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(CustomEditorInner), null);
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public CustomEditorInner()
{
this.Focused += (s,e) => FocusedCommand?.Execute(CommandParameter);
this.Unfocused += (s,e) => UnfocusedCommand?.Execute(CommandParameter);
}
}
<!-- CustomEditor.xaml -->
<?xml version = "1.0" encoding = "utf-8" ?>
<ContentView
x:Class = "Maui.StackOverflow.CustomEditor"
xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local = "clr-namespace:Maui.StackOverflow">
<ContentView.ControlTemplate>
<ControlTemplate>
<Border>
<local:CustomEditorInner
CommandParameter = "{TemplateBinding CommandParameter}"
FocusedCommand = "{TemplateBinding FocusedCommand}"
Placeholder = "CustomEditor"
UnfocusedCommand = "{TemplateBinding UnfocusedCommand}" />
</Border>
</ControlTemplate>
</ContentView.ControlTemplate>
</ContentView>
// CustomEditor.xaml.cs
using System.Windows.Input;
namespace Maui.StackOverflow;
public partial class CustomEditor : ContentView
{
public static readonly BindableProperty FocusedCommandProperty = BindableProperty.Create(nameof(FocusedCommand), typeof(ICommand), typeof(CustomEditor), null);
public ICommand FocusedCommand
{
get => (ICommand)GetValue(FocusedCommandProperty);
set => SetValue(FocusedCommandProperty, value);
}
public static readonly BindableProperty UnfocusedCommandProperty = BindableProperty.Create(nameof(UnfocusedCommand), typeof(ICommand), typeof(CustomEditor), null);
public ICommand UnfocusedCommand
{
get => (ICommand)GetValue(UnfocusedCommandProperty);
set => SetValue(UnfocusedCommandProperty, value);
}
public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create(nameof(CommandParameter), typeof(object), typeof(CustomEditor), null);
public object CommandParameter
{
get => GetValue(CommandParameterProperty);
set => SetValue(CommandParameterProperty, value);
}
public CustomEditor()
{
InitializeComponent();
}
}
<!-- EditorPage.xaml -->
<?xml version = "1.0" encoding = "utf-8" ?>
<ContentPage
x:Class = "Maui.StackOverflow.EditorPage"
xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local = "clr-namespace:Maui.StackOverflow"
x:Name = "thisPage"
Title = "EditorPage"
x:DataType = "local:EditorPage">
<VerticalStackLayout Spacing = "20">
<Entry Placeholder = "Entry1" />
<local:CustomEditor
CommandParameter = "{Binding Magic}"
FocusedCommand = "{Binding MyFocusedCommand}"
UnfocusedCommand = "{Binding MyUnfocusedCommand}" />
<Entry Placeholder = "Entry2" />
</VerticalStackLayout>
</ContentPage>
// EditorPage.xaml.cs
using System.Diagnostics;
using CommunityToolkit.Mvvm.Input;
namespace Maui.StackOverflow;
public partial class EditorPage : ContentPage
{
[RelayCommand]
void MyFocused(int magic)
{
Debug.WriteLine($"OnFocused magic:{magic}");
}
[RelayCommand]
void MyUnfocused(int magic)
{
Debug.WriteLine($"OnUnfocused magic:{magic}");
}
public int Magic { get; set; } = 42;
public EditorPage()
{
InitializeComponent();
BindingContext = this;
}
}
Обновлен ответ, добавляющий CommandParameter в CustomEditorInner и распространяющий его через CustomEditor и ContentPage.
Магия, спасибо, Стивен. Оцените свои усилия.
Привет! Большое спасибо, что потрудились написать подробный ответ! Очень ценю. Мне удалось заставить команду Unfocused работать, используя второй метод (поскольку он ближе к тому, что я пробовал до сих пор). Единственная проблема сейчас в том, что у меня есть модель в качестве параметра в RelayCommand. В настоящее время он установлен как BindingContext для ContentView «CustomEditor», но когда RelayCommand «MyUnfocused» срабатывает, параметр имеет значение null... Я понимаю, почему это так, но я не уверен, как это исправить. Можете ли вы помочь? Еще раз спасибо.