C# 如何为显式实现的接口设置DisplayMemberPath?
我的C# 如何为显式实现的接口设置DisplayMemberPath?,c#,wpf,C#,Wpf,我的User类显式地实现了IUser接口。此类为内部,但接口为公共。在另一个程序集中,我获取IEnumerable数据,并尝试将其设置为WPF元素的数据源 我使用的DisplayMemberPath属性有问题 这是我的界面: public interface IUser { string Name { get; set; } string MiddleName { get; set; } string Surname { get; set; } } 这是我的用户课
User
类显式地实现了IUser
接口。此类为内部
,但接口为公共
。在另一个程序集中,我获取IEnumerable
数据,并尝试将其设置为WPF元素的数据源
我使用的DisplayMemberPath
属性有问题
这是我的界面:
public interface IUser {
string Name { get; set; }
string MiddleName { get; set; }
string Surname { get; set; }
}
这是我的用户
课程:
internal class User : IUser {
public User(string name, string middleName, string surname) {
IUser user = (IUser)this;
user.Name = name;
user.MiddleName = middleName;
user.Surname = surname;
}
string name;
string IUser.Name {
get {
return name;
}
set {
if (IsValidName(value)) {
name = value?.Trim();
}
else {
throw new ArgumentException(nameof(IUser.Name));
}
}
}
private bool IsValidName(string value) {
if (string.IsNullOrEmpty(value)) {
return false;
}
string tmp = value.Trim();
if (tmp.All(n => char.IsLetter(n))) {
return true;
}
return false;
}
string middleName;
string IUser.MiddleName {
get {
return middleName;
}
set {
if (IsValidName(value)) {
middleName = value?.Trim();
}
else {
throw new ArgumentException(nameof(IUser.MiddleName));
}
}
}
string surname;
string IUser.Surname {
get {
return surname;
}
set {
if (IsValidName(value)) {
surname = value?.Trim();
}
else {
throw new ArgumentException(nameof(IUser.Surname));
}
}
}
}
这是我的IUser
代码,使用:
IFactory factory = Factory.Current;
IProjectDataProvider provider = factory.CreateProjectDataProvider()
;
// Get data sources
IEnumerable<IUser> users = provider.GetProjectMainArchitects();
Window win = new Window();
ComboBox cbox = new ComboBox();
cbox.Width = 200;
cbox.Height = 20;
cbox.HorizontalAlignment = HorizontalAlignment.Center;
cbox.VerticalAlignment = VerticalAlignment.Center;
win.Content = cbox;
Binding bind = new Binding();
bind.Source = users;
cbox.SetBinding(ItemsControl.ItemsSourceProperty, bind);
// cbox.DisplayMemberPath = "Name";
Application app = new Application();
app.Run(win);
IFactory factory=factory.Current;
IProjectDataProvider provider=factory.CreateProjectDataProvider()
;
//获取数据源
IEnumerable users=provider.GetProjectMainArchitects();
win窗口=新窗口();
ComboBox cbox=新ComboBox();
cbox.宽度=200;
cbox.高度=20;
cbox.HorizontalAlignment=HorizontalAlignment.Center;
cbox.VerticalAlignment=垂直对齐.中心;
win.Content=cbox;
绑定=新绑定();
bind.Source=用户;
cbox.SetBinding(ItemsControl.ItemsSourceProperty,bind);
//cbox.DisplayMemberPath=“Name”;
应用程序app=新应用程序();
应用程序运行(win);
结果是:
但是如果我取消注释//cbox.DisplayMemberPath=“Name”代码>代码行然后我得到这样的结果:
如何解决此问题?就像我说的,您必须至少公开您的Name属性才能从另一个程序集访问它。也许此链接有助于您了解问题:
简短形式:您可以在另一个程序集中访问接口,但当显式类型位于另一个程序集和内部时,不能访问它的属性
因为绑定需要公共访问,所以无法看到名称。问题不在于类的可见性,而在于明确实现了接口。从可见性的角度来看,显式实现相当于它是私有的(实际上它比私有的更糟糕,因为您只能通过显式转换从类本身内部调用它)
绑定只能看到公共成员,因此无法看到类的显式实现成员。(省略公共修饰符是一个提示!)
通常需要显式实现某些内容的唯一原因是名称冲突
请尝试以下操作以查看问题:
代码隐藏:
public interface IBlah
{
string ExplicitMember { get; set; }
string Member { get; set; }
}
public partial class MainWindow : IBlah
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
string IBlah.ExplicitMember { get; set; } = "Hidden";
public string Member { get; set; } = "Visible";
}
在XAML中:
<Window
x:Class="ExplicitBind.MainWindow"
Title="MainWindow"
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"
xmlns:local="clr-namespace:ExplicitBind"
Height="350"
Width="525"
mc:Ignorable="d">
<StackPanel>
<TextBox Text="{Binding ExplicitMember}" />
<TextBox Text="{Binding Member}" />
</StackPanel>
</Window>
设置DisplayMemberPath
属性对于显式实现的属性不起作用
您应该使用显式绑定到显式实现的属性的TextBlock
定义一个ItemTemplate
这在XAML中很容易做到:
<ComboBox>
<ComboBox.ItemTemplate>
<DataTemplate xmlns:local="clr-namespace:WpfApplication1;assembly=WpfApplication1">
<TextBlock Text="{Binding (local:IUser.Name)}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
不要忘记将“WpfApplication1”替换为定义了IUser
接口的名称空间和程序集的实际名称。我想您已经尝试将用户类公开,不是吗?或者它与您的视图在同一个程序集中?User
类将是internal
,hi是。我的第二个代码示例位于其他程序集中。我这样做是为了让工作严格通过接口来执行。这就解释了为什么在第二个示例中看不到任何东西。因为另一个程序集无权访问您的用户类及其属性。我将IEnumerable
作为数据源IUser
实例可供使用,因为此接口声明为public
。解决此问题的简单方法是将Name
公开(User
类在此情况下仍然可以是内部的)。所有对属性的访问都是通过反射完成的,所以在这种情况下,是否传递类或接口实例无关紧要。WPF将(基本上)执行GetType().GetProperty(“名称”)。同意您所说的一切,除非有其他原因需要显式实现。也许你想隐藏一个与你的类型不相关的成员,例如过时的。非常同意!您需要显式实现的唯一原因是名称冲突,但也有一些架构原因,您可能希望强制某人进行强制转换以调用。(目前情况相当冷淡,投票表决如何?)我隐藏了实现,以便于测试和替换实现。我尝试使用它:cbox.ItemTemplate=XamlReader.Parse(“”)作为数据模板代码>但它不起作用。“不起作用”是什么意思?您是否遇到异常或发生了什么?你的程序集真的被命名为“Core”吗?这意味着我得到了与我在第二个屏幕上显示的相同的无效结果。不,我也不例外。是的,它的名称是Core.dll
。那么,在设置ItemTemplate属性时,您在组合框中看到了什么?出于测试目的,尝试将XAML中TextBlock的Text属性设置为静态字符串。如果没有看到此文本,则表示尚未应用ItemTemplate。请用完整回购更新您的问题。
cbox.SetBinding(ItemsControl.ItemsSourceProperty, bind);
cbox.ItemTemplate = System.Windows.Markup.XamlReader.Parse("<DataTemplate xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\" xmlns:local=\"clr-namespace:WpfApplication1;assembly=WpfApplication1\"><TextBlock Text=\"{Binding (local:IUser.Name)}\" /></DataTemplate>") as DataTemplate;
this.Content = cbox;