【问题标题】:Specify .XAML part of UserControl in code-behind在代码隐藏中指定 UserControl 的 .XAML 部分
【发布时间】:2015-01-26 20:13:00
【问题描述】:

我编写了自定义TreeView 控件。

XAML:

<TreeView x:Class="EArchiveMaster.View.MyTreeView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <TreeView.ItemContainerStyle>
        <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
            <EventSetter Event="LostFocus" Handler="EventSetter_OnHandler" />
        </Style>
    </TreeView.ItemContainerStyle>
</TreeView>

.cs

public partial class MyTreeView
{
    public event Action SomeItemLostFocus;

    public MyTreeView()
    {
        InitializeComponent();
    }

    private void EventSetter_OnHandler(object sender, RoutedEventArgs e)
    {
        e.Handled = true;
        if (SomeItemLostFocus != null)
            SomeItemLostFocus();
    }
}

但是当我尝试使用它时,我得到了众所周知的错误:

无法在元素“TextBox”上设置名称属性值“TextBox”。 “TextBox”在元素“MyTreeView”的范围内,当它在另一个范围内定义时,它已经注册了一个名称。

我找到了一些收据来解决这个错误。即,在其代码隐藏中指定控制的 .xaml 部分。 但我不知道我该怎么做。

【问题讨论】:

  • 已经有一个相同的question for WPF。大多数答案也适用于您的情况。此外,您没有显示将Name 设置为TextBox 的位置。
  • @icebat 我将Name 设置为TextBox 的位置无关紧要。问题是“如何在其代码隐藏中指定控制的 .xaml 部分”。你能帮忙吗?
  • @icebat 我已经看到了这个问题,但我不明白在我的情况下我应该在OnInitialized 方法中写什么......

标签: c# wpf xaml code-behind


【解决方案1】:

代码清楚地表明您想要扩展 TreeView。基本上,如果您想构建可以保存一些内容(可以命名...)的控件,例如 ContentControl、ItemsControl 等。使用 CustomControl 总是更好。带有 XAML 和 CS 代码的 UserControl 不适合这种情况。

在您的情况下,创建一个如下所示的类并扩展功能,

public class MyTreeView : TreeView
{
    public event Action SomeItemLostFocus;

    public MyTreeView()
    {
        DefaultStyleKey = typeof(MyTreeView);
    }

    public override void OnLostFocus(object sender, RoutedEventArgs e)
    {
        e.Handled = true;
        if (SomeItemLostFocus != null)
            SomeItemLostFocus();
    }
}

如果你想自定义外观,你应该覆盖控件的默认样式。此样式应在 Themes 文件夹内的 generic.xaml 文件中可用。有关自定义控件开发的更多信息是here

     <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded"
                Value="{Binding IsExpanded, Mode=TwoWay}" />
        <Setter Property="IsSelected"
                Value="{Binding IsSelected, Mode=TwoWay}" />
    </Style>

【讨论】:

  • 你看到问题了吗?因为,你几乎只是复制粘贴了我的代码
  • 没有。您的代码是用户控件。我的代码是自定义控件。您的代码与 XAML 一起具有部分类。我的代码具有从 TreeView 扩展的独立类。我的代码不会抛出 NameScope 错误。
  • 好的,但您的样式不包含&lt;EventSetter Event="LostFocus" Handler="EventSetter_OnHandler" /&gt;。这个字符串非常重要。如果Style 将与.cs 分开定义,我将无法使用EventSetter,因为它需要事件处理程序。
  • 您可以使用 OnLostFocus 覆盖方法,而不是使用 Eventhandler。
  • 只是不明白你的OnLostFocus 方法将如何被调用,当TreeViewITEM 的LostFocus 事件将上升时。它们之间的联系在哪里?
【解决方案2】:

我找到了适合我的解决方案。这就是如何在代码中而不是在 XAML 中定义 TreeViewItemStyle 的方式。现在我只在代码隐藏中定义了TreeView,因此不会出现错误。

public class MyTreeView : TreeView
{
    public event RoutedEventHandler ItemLostLogicFocus;

    protected override void OnInitialized(EventArgs e)
    {
        base.OnInitialized(e);

        var itemContainerStyle = new Style
        {
            TargetType = typeof(TreeViewItem),
        };

        #region Binding

        var expandedBinding = new Binding("IsExpanded")
        {
            Mode = BindingMode.TwoWay,
        };

        var selectedBinding = new Binding("IsSelected")
        {
            Mode = BindingMode.TwoWay,
        };

        #endregion

        #region Setters

        itemContainerStyle.Setters.Add(new Setter
        {
            Property = TreeViewItem.IsExpandedProperty,
            Value = expandedBinding
        });
        itemContainerStyle.Setters.Add(new Setter
        {
            Property = TreeViewItem.IsSelectedProperty,
            Value = selectedBinding
        });

        #endregion

        #region EventSetters

        itemContainerStyle.Setters.Add(new EventSetter
        {
            Event = LostFocusEvent,
            Handler = new RoutedEventHandler(ItemLostLogicFocusHandler)

        });

        #endregion

        ItemContainerStyle = itemContainerStyle;
    }

    private void ItemLostLogicFocusHandler(Object sender, RoutedEventArgs e)
    {
        e.Handled = true;
        if (ItemLostLogicFocus != null)
            ItemLostLogicFocus(sender, e);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 2012-07-15
    • 2010-11-03
    • 2015-12-30
    • 2019-06-07
    • 1970-01-01
    • 2011-04-21
    相关资源
    最近更新 更多