以下是实现与您需要做的类似的多个绑定的三种方法。
1)一个包装类:
public class ProfileUserWrapper : DependencyObject
{
public ProfileUserWrapper(ProfileUser thebrain) { TheUser = thebrain; }
public ProfileUser TheUser { get; private set; }
public Operator User { get { if (_user != null)return _user; return _user = OperatorManager.GetByGuId(TheUser.User_ID); } }
private Operator _user = null;
}
现在,public EntityCollection<ProfileUser> ProfileUsers
您可以公开例如IEnumerable<ProfileUserWrapper>
:
public EntityCollection<ProfileUser> ProfileUsers // your original code
{
get{ if (profile != null) return profile.ProfileUser; else return null;}
set { profile.ProfileUser = value; }
}
public IEnumerable<ProfileUserWrapper> ProfileUsers2
{
get { return ProfileUsers.Select(user => new ProfileUserWrapper(user));
}
然后绑定到 ProfileUsers2,并且您的一些绑定应该从“Address”更改为“TheUser.Address”,但这几乎肯定会起作用。
2)第二个,智能转换器,例如:
public class OperatorPicker : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var pu = value as ProfileUser;
if (pu != null)
return OperatorManager.GetByGuId(pu.User_ID);
return null;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
写起来几乎再简单不过了。现在您可以在 XAML 绑定中使用转换器:
<Window.Resources>
<myextra:OperatorPicker x:Key="conv1" />
</Window.Resources>
<Grid>
<ListBox x:Name="lbxFirst" ItemsSource="{Binding ProfileUsers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Margin="5" Text="{Binding User_ID}" />
<TextBlock Margin="5" Text="{Binding Login}" />
<TextBlock Margin="5" Text="{Binding Address}" />
<TextBlock Margin="5" Text="{Binding Path=., Converter={StaticResource conv1}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
但是这样一来,你就会得到Operator
它自己的对象。允许您绑定到以这种方式返回的运算符的属性将非常困难,因为 Binding 的路径已经固定在“。”,并且您无法更改它,因为必须向 Converter 传递 ProfileUser 实例。
3) 第三,最复杂但完全没有任何包装器的工作是基于附加属性、转换器和两个绑定,但您也可以在两个附加属性和一个更改回调上执行此操作。我更喜欢前一种方式,所以这里是:
public class DummyClass : DependencyObject
{
public static readonly DependencyProperty TheOperatorProperty = DependencyProperty.RegisterAttached(
"TheOperator", typeof(Operator), typeof(DummyClass),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender)
);
public static Operator GetTheOperator(DependencyObject elem) { return (Operator)elem.GetValue(TheOperatorProperty); }
public static void SetTheOperator(DependencyObject elem, Operator value) { elem.SetValue(TheOperatorProperty, value); }
}
... xmlns:myextra="clr-namespace:...." ....
<Window.Resources>
<myextra:OperatorPicker x:Key="conv1" />
</Window.Resources>
<Grid>
<ListBox x:Name="lbxFirst" ItemsSource="{Binding ProfileUsers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="aparent" Orientation="Horizontal"
myextra:DummyClass.TheOperator="{Binding Path=., Converter={StaticResource conv1}}">
<TextBlock Margin="5" Text="{Binding User_ID}" />
<TextBlock Margin="5" Text="{Binding Login}" />
<TextBlock Margin="5" Text="{Binding Address}" />
<TextBlock Margin="5"
Text="{Binding Path=(myextra:DummyClass.TheOperator).OperatorCodename, ElementName=aparent}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
请注意,在 StackPanel 级别有一个新的绑定。这个可以放在数据模板中的任何地方,甚至是文本框本身。请注意它如何通过转换器将 ProfileUser 转换为 Operator。Path=.
不是必需的,但我添加了它以便显示绑定的确切含义。请注意最后一个文本框绑定是如何指定的:它是对附加属性的绑定(通过元素名称),而不是对原始数据的绑定!
这次我测试了所有东西,它在我这边工作,在 ProfileUser 上没有 DependencyObject 继承。DummyClass
它对继承感到满意。如果你尝试这个,请像往常一样给我留言:)