C# 通过ContentTemplate在样式触发器中生成的聚焦元素

C# 通过ContentTemplate在样式触发器中生成的聚焦元素,c#,wpf,textbox,datatemplate,routedevent,C#,Wpf,Textbox,Datatemplate,Routedevent,通过使用WPF,我试图生成一个文本块,双击该文本块后,“转换”为一个文本框,以便进行编辑。之后,回车键、Esc键或失去焦点会导致编辑结束,文本框恢复为文本块 我找到的解决方案基本上是有效的。我的问题是,我无法将文本框的焦点放在“转换”上,从而迫使用户再次显式单击元素以将其聚焦并开始编辑 守则的解释 我选择的实现此行为的方式是使用模板和样式的DataTrigger来更改元素的模板。在我展示的示例中,元素是一个简单的ContentControl,尽管我尝试这样做的实际用例要复杂得多(我有一个列表框,

通过使用WPF,我试图生成一个文本块,双击该文本块后,“转换”为一个文本框,以便进行编辑。之后,回车键、Esc键或失去焦点会导致编辑结束,文本框恢复为文本块

我找到的解决方案基本上是有效的。我的问题是,我无法将文本框的焦点放在“转换”上,从而迫使用户再次显式单击元素以将其聚焦并开始编辑

守则的解释 我选择的实现此行为的方式是使用模板和样式的DataTrigger来更改元素的模板。在我展示的示例中,元素是一个简单的ContentControl,尽管我尝试这样做的实际用例要复杂得多(我有一个列表框,其中每个元素都可以通过这种行为一次编辑一个)

其思路如下:

  • ContentControl具有关联的样式
  • 关联的样式将ContentTemplate定义为TextBlock
  • 模型对象有一个属性InEditing,当我想要编辑控件时,该属性将变为true
  • 通过在TextBlock上的鼠标指针,我将模型的InEdit属性设置为True
  • 样式有一个DataTrigger,它侦听InEdit,在本例中,它将ContentTemplate设置为文本框
  • 通过eventsetter,我捕获Enter、Esc和LostFocus,以便恢复保存更改并恢复到以前的样式。请注意:我不能直接将事件附加到文本框,否则我会得到一个警告,即不能在样式中的目标标记上指定事件。改用事件设置器
虽然不是最优的(视图和模型行为有一定的混合-尤其是在InEdit属性中-并且我不喜欢通过KeyDown和LostFocus的各种处理程序实质性地重新实现文本框模型更改的提交逻辑),但系统实际上可以正常工作

失败的实施理念 起初,我想连接到文本框的IsVisibleChanged事件,并在其中设置焦点。无法执行此操作,因为前面提到的错误,无法在样式中的目标标记上指定事件。改用事件设置器

无法使用错误建议的解决方案,因为此类事件不是路由事件,因此无法在EventSetter中使用

代码 代码分为四个文件

Model.cs:
使用System.Windows;
名称空间LeFocus
{
公共类模型:DependencyObject
{
公共图书馆编辑
{
获取{return(bool)GetValue(InEditingProperty);}
set{SetValue(InEditingProperty,value);}
}
//使用DependencyProperty作为InEdit的备份存储。这将启用动画、样式、绑定等。。。
public static readonly dependencProperty InEdit属性=
DependencyProperty.Register(“InEdit”、typeof(bool)、typeof(Model)、new UIPropertyMetadata(false));
公共字符串名
{
获取{return(string)GetValue(NameProperty);}
set{SetValue(NameProperty,value);}
}
//使用DependencyProperty作为Name的后备存储。这将启用动画、样式、绑定等。。。
公共静态只读DependencyProperty NameProperty=
Register(“Name”、typeof(string)、typeof(Model)、newUIPropertyMetadata(“Hello!”);
}
}
App.xaml:

MainWindow.xaml:

MainWindow.xaml.cs
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
名称空间LeFocus
{
/// 
///MainWindow.xaml的交互逻辑
/// 
公共部分类主窗口:窗口
{
公共主窗口()
{
初始化组件();
}
公共字符串名称编辑
{
获取{return(string)GetValue(NameInEditingProperty);}
set{SetValue(NameInEditingProperty,value);}
}
//使用DependencyProperty作为NameInEdit的备份存储。这将启用动画、样式、绑定等。。。
公共静态只读从属属性NameInEditingProperty=
Register(“NameInEditing”、typeof(string)、typeof(MainWindow)、new-UIPropertyMetadata(null));
公共静态只读RoutedUICommand和EditName=
新的RoutedUICommand(“EditName”、“EditName”、typeof(MainWindow));
私有void setInEditing(对象发送方,ExecutedRoutedEventArgs e)
{
var模型=((模型)e.参数);
NameInEditing=model.Name;
model.InEditing=true;
}
私有void文本框\u KeyDown(对象发送方,KeyEventArgs e)
{
如果(e.Key==Key.Enter)
{
var model=getModelFromSender(sender);
model.Name=NameInEditing;
NameInEditing=null;
model.InEditing=false;
}
else if(e.Key==Key.Escape)
{
var model=getModelFromSender(sender);
model.InEditing=false;
}
}
私有无效文本框\u LostFocus(对象发送方,RoutedEvent
<Page.Resources>
    <ResourceDictionary>

        <Style x:Key="NullSelectionStyle" TargetType="ListBoxItem">
            <Style.Resources>
                <!-- SelectedItem with focus -->
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent" />
                <!-- SelectedItem without focus -->
                <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
                <!-- SelectedItem text foreground -->
                <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}" Color="{DynamicResource {x:Static SystemColors.ControlTextColorKey}}" />
            </Style.Resources>
            <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        </Style>

        <Style x:Key="ListBoxSelectableTextBox" TargetType="{x:Type TextBox}">
            <Setter Property="IsHitTestVisible" Value="False" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}, AncestorLevel=1}}" Value="True">
                    <Setter Property="IsHitTestVisible" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</Page.Resources>
<Grid>
    <ListBox ItemsSource="{Binding Departments}" HorizontalContentAlignment="Stretch">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBox Margin="5" Style="{StaticResource ListBoxSelectableTextBox}" Text="{Binding Name}" BorderBrush="{x:Null}"/>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>