- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我一直在研究 WPF 和 MVVM,并注意到一件奇怪的事情。在自定义用户控件上使用 {Binding ElementName=...}
时,用户控件中根元素的名称似乎在使用该控件的窗口中可见。比如说,这是一个示例用户控件:
<UserControl x:Class="TryWPF.EmployeeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TryWPF"
Name="root">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding}"/>
<Button Grid.Column="1" Content="Delete"
Command="{Binding DeleteEmployee, ElementName=root}"
CommandParameter="{Binding}"/>
</Grid>
</UserControl>
在我看来非常合法。现在,依赖属性 DeleteEmployee
在代码隐藏中定义,如下所示:
public partial class EmployeeControl : UserControl
{
public static DependencyProperty DeleteEmployeeProperty
= DependencyProperty.Register("DeleteEmployee",
typeof(ICommand),
typeof(EmployeeControl));
public EmployeeControl()
{
InitializeComponent();
}
public ICommand DeleteEmployee
{
get
{
return (ICommand)GetValue(DeleteEmployeeProperty);
}
set
{
SetValue(DeleteEmployeeProperty, value);
}
}
}
这里没有什么神秘的。然后,使用该控件的窗口如下所示:
<Window x:Class="TryWPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TryWPF"
Name="root"
Title="Try WPF!" Height="350" Width="525">
<StackPanel>
<ListBox ItemsSource="{Binding Employees}" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<local:EmployeeControl
HorizontalAlignment="Stretch"
DeleteEmployee="{Binding DataContext.DeleteEmployee, ElementName=root}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Window>
同样,没有什么特别的……除了窗口和用户控件具有相同的名称!但我希望 root
在整个窗口 XAML 文件中表示相同的内容,因此指的是窗口,而不是用户控件。唉,当我运行它时打印了以下消息:
System.Windows.Data Error: 40 : BindingExpression path error: 'DeleteEmployee' property not found on 'object' ''String' (HashCode=-843597893)'. BindingExpression:Path=DataContext.DeleteEmployee; DataItem='EmployeeControl' (Name='root'); target element is 'EmployeeControl' (Name='root'); target property is 'DeleteEmployee' (type 'ICommand')
DataItem='EmployeeControl' (Name='root')
让我认为它将 ElementName=root
视为指代控件本身。它在 string
上查找 DeleteEmployee
的事实证实了这种怀疑,因为 string
正是我设计的 VM 中的数据上下文。为了完整起见,这里是:
class ViewModel
{
public ObservableCollection<string> Employees { get; private set; }
public ICommand DeleteEmployee { get; private set; }
public ViewModel()
{
Employees = new ObservableCollection<string>();
Employees.Add("e1");
Employees.Add("e2");
Employees.Add("e3");
DeleteEmployee = new DelegateCommand<string>(OnDeleteEmployee);
}
private void OnDeleteEmployee(string employee)
{
Employees.Remove(employee);
}
}
它在构造函数中被实例化并分配给窗口,这是窗口代码隐藏中唯一的东西:
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
这种现象引发了以下问题:
Name
根本不应该在自定义控件中使用?FindAncestor
模式下使用 {RelativeSource}
,这工作正常,但有更好的方法吗?最佳答案
你对如何wpf namescopes感到困惑在这种情况下工作是可以理解的。
您的问题只是您正在对 UserControl 应用绑定(bind),它是其自己名称范围的“根”(可以这么说)。 UserControl 和几乎所有容器对象都有自己的名称范围。这些范围不仅包含子元素,还包含包含名称范围的对象。这就是为什么您可以将 x:Name="root"
应用到您的窗口并(除了这种情况)从子控件中定位它的原因。如果您不能,名称范围将毫无用处。
当您在包含的名称范围内对名称范围的根进行操作时,就会出现混淆。您的假设是父级的名称范围具有优先权,但事实并非如此。 Binding 在目标对象上调用 FindName,在您的情况下是您的用户控件。 (旁注,Binding 没有做 jack,实际调用可以在 ElementObjectRef.GetObject
中找到,但这是 Binding 将调用委托(delegate)给的地方)
当您在名称范围的根上调用 FindName
时,只会检查在此范围内定义的名称。 不搜索父范围。 (编辑...更多阅读源代码 http://referencesource.microsoft.com/#PresentationFramework/src/Framework/MS/Internal/Data/ObjectRef.cs,5a01adbbb94284c0 从第 46 行开始,我看到算法沿着可视化树向上移动,直到找到目标,因此子作用域优先于父作用域)
所有这一切的结果是您获得了用户控件实例而不是窗口,就像您希望的那样。现在,回答您的个人问题...
1. Is this by design?
是的。否则名称范围将无法工作。
2. If so, how is someone using a custom control supposed to know what name it uses internally?
理想情况下,您不会。就像您永远不想必须知道 TextBox
的根名称一样。不过,有趣的是,在尝试修改控件的外观和感觉时,了解控件中定义的模板的名称通常很重要...
3. If Name is not supposed to be used in custom control at all? If so, then what are the alternatives? I switched to using {RelativeSource} in FindAncestor mode, which is working fine, but are there better ways?
不!没关系。用它。如果您不与其他人共享您的 UserControl,请确保在遇到此特定问题时更改其名称。如果您没有任何问题,请整天重复使用相同的名称,这不会造成任何伤害。
如果您要共享您的 UserControl,您应该将其重命名为不会与其他人的名称冲突的名称。称它为 MuhUserControlTypeName_MuhRoot_Durr 或其他名称。
4. If so, then what are the alternatives? I switched to using {RelativeSource} in FindAncestor mode, which is working fine, but are there better ways?
不。只需更改用户控件的 x:Name
并继续。
5. Does this have anything to do with the fact that data templates define their own names copes? It doesn't stop me from referring to the main window from within a template if I just rename it so the name doesn't clash with the control.
不,我不这么认为。无论如何,我认为没有任何充分的理由。
关于c# - WPF 用户控件和名称范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38619921/
我想实现自定义搜索,但遇到了一个麻烦。我需要将 UIButton、SearchBar 组合在一个控件中,以便我可以通过指针引用它。然后我将向该组合控件动态添加更多 UIbutton。最重要的是,我想将
它没有在我的方法中执行 if block 中的语句 母版页:- 页面加载事件:- Control c = new Control(); DoSomething(c); 我的方法:- protecte
ComboBox 控件有一个 setConverter 方法,请参阅 JavaFX ComboBox - Display text but return ID on selection举个例子。我正在
我没有找到任何包含用于标记化(标记)文本输入的控件的 wpf 库。也许我找不到库,因为我错误地调用了这个组件。怎么叫或者哪里有这样的库? 最佳答案 DevExpress WPF 库包含多个数据编辑控件
是否有 Silverlight 控件允许您输入文本并将其突出显示为代码? 例如: foreach (client in Clients){ client.Save();} would become
我有以下用户控件 a) Panel.ZIndex="99999999" 是否是将此控件设置为该控件中 TopMost 的正
是否可以在 Windows 窗体中使用 C# 在窗体加载时隐藏所有特定控件,例如标签或按钮,然后选择显示我不想显示的那些? 我有一个包含很多按钮和标签的程序,但我只想在加载时显示一两个,我觉得对每个标
这个问题已经有答案了: 已关闭11 年前。 Possible Duplicate: Duplicating components at Run-Time 我有一个TMyControl ( Contro
我正在尝试在 Delphi 中编写一个 dll 库,其中包含一个创建 TFrame 后代实例并返回它的函数。但是当我在应用程序中导入这个函数时,每次调用它时,我都会得到一个异常,例如“'xxx'控件没
是否有 Win32 API 调用来确定哪些窗口和/或控件在特定坐标和/或鼠标下可见? 最佳答案 您可以使用GetWindowFromPoint 。它将返回窗口句柄,以便您可以使用 GetClassNa
我需要在编辑控件中输入以下公式: 公式是在 MS Word 中制作的。尝试将其复制/粘贴到编辑控件(单行或多行)后,我得到 M 0.33 Q10T9.1-9.7。 当我输入这个时,我正在研究 Rich
我只是想成功地将它添加到我的窗口中,但这却出奇地困难。 我已经尝试过 #include "windef.h" #include "winbase.h" #include "initguid.h" #i
我希望能够使用 google maps api v3 拥有自己的“街景”按钮。单击按钮时,我希望它根据我的标记经纬度加载街景。然后我希望按钮更改为“返回 map ”,然后再次加载默认 map View
我目前正在用 PHP 开发(另一个)开源 CMS,我想使用 javascript 控件,尤其是管理面板。问题是,是否有任何具有 PHP 接口(interface)的开源、可自由分发的控件(用于创建 j
我为其编写软件的产品之一是会计类应用程序。它用 C++ 编写,使用 C++ Builder 和 VCL 控件,连接到运行在 Linux 上的 PostgreSQL 数据库。 PostgreSQL 数据
我使用 Key Listener 来读取用户的输入,但我遇到了问题。首先,我读到 JTextField“请输入您的姓名”。如果用户输入一个名字,例如 John,它将更改为 John。但是,如果用户输入
我正在尝试对齐数据表列中的复选框(h=center,v=middle) ... 但复选框仍然显示在错误的位置(见附图)
我有一个包含统计信息的 JSON 数据树: { prefix: "a", count: 20, children: [ { prefix: "a:b", c
我在 Photoshop 中设计了一个模型,我打算将它应用到我的产品目录的 ListView 控件中,但它似乎没有正确显示(未对齐?),我希望这里的人可以像我一样指出我的错误试图弄清楚无济于事。 预期
您是使用 ASP.NET 控件还是仅使用带有 CSS 的 HTML? 我在 TextBox 和 DropDownList 的宽度方面遇到了一些问题。在不同的浏览器中,宽度会有所不同,控件的大小也不会相
我是一名优秀的程序员,十分优秀!