英文:
How to use UserStoppedTypingBehavior from ControlTemplate?
问题
在我的.NET MAUI应用程序中,我创建了一个自定义搜索控件和其控件模板。当我运行应用程序并执行搜索时,SearchCommand没有被触发。
如果我直接将Entry控件添加到TestPage并添加行为,那么它就能正常工作。
<Entry Grid.Row="0"
HorizontalOptions="FillAndExpand"
Placeholder="在此输入...">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=SearchCommand}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
自定义控件
/// <summary>
/// 表示一个Entry控件,样式包含搜索图标,当输入文本更改时触发新的搜索命令。
/// </summary>
public class SearchField : MobileContentViewBase
{
// 自定义控件的逻辑
private Entry _searchFieldEntry;
private const string SearchFieldEntryName = nameof(_searchFieldEntry);
protected override void AddCustomHandlers()
{
if (_searchFieldEntry == null)
{
_searchFieldEntry = this.FindChildByClassId<Entry>(SearchFieldEntryName);
}
}
}
App.xaml
<ControlTemplate x:Key="SearchFieldTemplate">
<StackLayout>
<ctrls:IconButton
ImageSource="Search"
BackgroundColor="Transparent" />
<Entry
ClassId="_searchFieldEntry"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=BindingContext.SearchCommand}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
</StackLayout>
</ControlTemplate>
<Style TargetType="ctrls:SearchField">
<Setter Property="ControlTemplate" Value="{StaticResource Key=SearchFieldTemplate}" />
</Style>
TestPage.xaml
<myCtrl:SearchField
x:Name="searchField"
Grid.Row="0"
HorizontalOptions="FillAndExpand"
Placeholder="在此搜索..." />
TestPageViewModel.cs
public ICommand SearchCommand { get; set; }
public TestPageViewModel()
{
SearchCommand = new Command<string>(PerformSearch);
}
private void PerformSearch(string searchTerms)
{
PerformedSearches += $"搜索了 '{searchTerms}'{Environment.NewLine}";
}
除了简单的绑定外,我还尝试了使用位于SearchFieldTemplate中的Entry控件的TemplateBinding,但它会引发InvalidOperationException异常。
有没有人知道如何使其工作?任何帮助都将不胜感激。
英文:
In my .NET MAUI app, I have created a custom search control and ControlTemplate for it. When I'm running the app and perform search the SearchCommand is not getting fired.
If I add the Entry control directly to TestPage and add behavior then its working.
<Entry Grid.Row="0"
HorizontalOptions="FillAndExpand"
Placeholder="type here...">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=SearchCommand}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
Custom control
/// <summary>
/// Represents an Entry control styled to contain a search icon
/// and trigger a new search command when the entry text changes.
/// </summary>
public class SearchField : MobileContentViewBase
{
//Logic of custom control
private Entry _searchFieldEntry;
private const string SearchFieldEntryName = nameof(_searchFieldEntry);
protected override void AddCustomHandlers()
{
if (_searchFieldEntry == null)
{
_searchFieldEntry = this.FindChildByClassId<Entry>(SearchFieldEntryName);
}
}
}
App.xaml
<ControlTemplate x:Key="SearchFieldTemplate">
<StackLayout>
<ctrls:IconButton
ImageSource="Search"
BackgroundColor="Transparent" />
<Entry
ClassId="_searchFieldEntry"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=BindingContext.SearchCommand}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
</StackLayout>
</ControlTemplate>
<Style TargetType="ctrls:SearchField">
<Setter Property="ControlTemplate" Value="{StaticResource Key=SearchFieldTemplate}" />
</Style>
TestPage.xaml
<myCtrl:SearchField
x:Name="searchField"
Grid.Row="0"
HorizontalOptions="FillAndExpand"
Placeholder="Search here..." />
TestPageViewModel.cs
public ICommand SearchCommand { get; set; }
public TestPageViewModel()
{
SearchCommand = new Command<string>(PerformSearch);
}
private void PerformSearch(string searchTerms)
{
PerformedSearches += $"Performed search for '{searchTerms}'{Environment.NewLine}";
}
Instead of simple Binding I have tried TemplateBinding as well with Entry control which is in SearchFieldTemplate but it throws an InvalidOperationException
.
Does anyone know how to make it work? Any help will be highly appreciated.
答案1
得分: 1
行为没有唯一的可视树父级,因此我们无法在其上使用RelativeSource绑定。您还可以参考此问题:Relativesource绑定和行为。
解决方法:
尽管我们无法为行为使用RelativeSource绑定,但我们可以使用TemplateBinding来为Entry或StackLayout设置Binding,然后引用它。请考虑下面的代码:
在App.xaml中:
<Entry x:Name="myentry" BindingContext="{Binding BindingContext, Source={RelativeSource TemplatedParent}}"
ClassId="_searchFieldEntry"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=BindingContext.SearchCommand,Source={x:Reference myentry}}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
在上面的代码中,我们首先使用TemplateBinding来设置Entry的BindingContext(x:Name="myentry"
)。然后为行为设置Binding源为Entry。
希望这对您有所帮助。
英文:
Behaviours don't have unique visual tree parents so we cannot use RelativeSource binding on it. You could also refer to this issue: Relativesource bindings and behaviors.
Workaround:
Although we cannot use RelativeSource binding for behavior, we could use TemplateBinding for Entry or StackLayout, then refer to it. Consider the code below:
In App.xaml:
<Entry x:Name="myentry" BindingContext="{Binding BindingContext, Source={RelativeSource TemplatedParent}}"
ClassId="_searchFieldEntry"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<Entry.Behaviors>
<toolkit:UserStoppedTypingBehavior
Command="{Binding Path=BindingContext.SearchCommand,Source={x:Reference myentry}}"
StoppedTypingTimeThreshold="1000"
MinimumLengthThreshold="3"
ShouldDismissKeyboardAutomatically="True" />
</Entry.Behaviors>
</Entry>
In the above code, we first use TemplateBinding to set the BindingContext for Entry (x:Name="myentry"
). Then for Behavior set the Binding Source to the Entry.
Hope it works.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论