使用C#绑定到WPF中的UserControl
本文关键字:中的 UserControl WPF 绑定 使用 | 更新日期: 2023-09-27 18:03:41
前言我举的控件是一个较大项目的样例。我已经在Stackoverflow上得到了社区的一些帮助,解决了控件中绑定的一些细节。令人惊讶的是,我在控件的托管形式中遇到了绑定问题。
我已经阅读并研究了DependencyProperty很多小时了。今年年初,我不是WPF的开发人员,但由于公司的死亡,我现在正在报道这个角色,我承认这是一座需要攀登的大山。
问题是我的中缺少了什么
托管表单的XAML代码
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:AControl="clr-namespace:AControl;assembly=AControl" x:Class="DependencySampler.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Grid>
<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>
</Grid>
背后的代码
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new viewModelBinding();
BeSelected = new modelMain("Yellow", "#FFFFE0");
}
public modelMain BeSelected
{
get { return ((viewModelBinding)DataContext).Selected; }
set { ((viewModelBinding)DataContext).Selected = value; }
}
}
ViewModel
public class viewModelBinding :ViewModelBase
{
modelMain sel = new modelMain("Red", "#FF0000");
public modelMain Selected
{
get { return sel; }
set { SetProperty(ref this.sel, value, "Selected"); }
}
}
下一节是控件本身。
型号
public class modelMain:ViewModelBase
{
public modelMain(string colName, string hexval)
{
ColorName = colName;
HexValue = hexval;
}
string colorName;
public string ColorName
{
get { return colorName; }
set { SetProperty(ref this.colorName, value, "ColorName"); }
}
string hexValue;
public string HexValue
{
get { return hexValue; }
set { SetProperty(ref this.hexValue, value, "HexValue"); }
}
}
ViewModel
public class viewModelMain:ViewModelBase
{
ObservableCollection<modelMain> val = new ObservableCollection<modelMain>();
public ObservableCollection<modelMain> ColorsList
{
get { return val; }
set { SetProperty(ref this.val, value, "Colors"); }
}
modelMain selectedColor;
public modelMain SelectedColour
{
get{return selectedColor;}
set { SetProperty(ref this.selectedColor, value, "SelectedColour"); }
}
public void SetCurrentColor(modelMain col)
{
SelectedColour = this.val.Where(x => x.ColorName == col.ColorName).FirstOrDefault();
}
public viewModelMain()
{
val.Add(new modelMain("Red", "#FF0000"));
val.Add(new modelMain("Blue", "#0000FF"));
val.Add(new modelMain("Green", "#008000"));
val.Add(new modelMain("Yellow", "#FFFFE0"));
SelectedColour = new modelMain("Blue", "#0000FF");
}
}
UserControl XAML
<UserControl x:Class="AControl.UserControl1"
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="32" d:DesignWidth="190">
<Grid>
<ComboBox x:Name="cboValue"
SelectionChanged="cboValue_SelectionChanged"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding ColorList, RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedValue="{Binding SelectedColor, RelativeSource={RelativeSource AncestorType=UserControl}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Width="10"
Height="10"
Margin="5"
Background="{Binding ColorName}"/>
<TextBlock Width="35"
Height="15"
Margin="5"
Text="{Binding ColorName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
背后的用户控制代码
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
ObservableCollection<modelMain> colorList = new viewModelMain().ColorsList;
public ObservableCollection<modelMain> ColorList
{
get { return colorList; }
set { colorList = value; }
}
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register(
"SelectedColor",
typeof(modelMain),
typeof(UserControl1),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnSelectedColorChanged),
new CoerceValueCallback(CoerceSelectedColorCallback)));
private static void OnSelectedColorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UserControl1 uc = (UserControl1)d;
uc.SelectedColor = (modelMain)e.NewValue;
}
private static object CoerceSelectedColorCallback(DependencyObject d, object value)
{
return (modelMain)value;
}
public modelMain SelectedColor
{
get { return (modelMain)GetValue(SelectedColorProperty); }
set { SetValue(SelectedColorProperty, value); }
}
private void cboValue_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var dat = sender as ComboBox;
SelectedColor = (modelMain)dat.SelectedValue;
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
//var dat = sender as ComboBox;
////SelectedColor = (modelMain)dat.SelectedValue;
//SelectedColor = (modelMain)this.SelectedColor;
}
}
请注意,在后面的代码中有未使用的代码,但在我当时用于放置断点的样本中
我知道UserControl中不应该存在DataContext,因为它排除了宿主形式中的DataContext
问题我原以为这条线在托管形式下就足够了。
<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, Mode=OneWayToSource}"/>
但它似乎并没有达到我的预期。我可以看到BeSelected被初始化,它包含一个值,但当表单加载时,我希望黄色进入UserControl并设置DependencyPropertySelectedColor。这种情况没有发生,为什么以及如何才能实现?
要让您的示例工作起来,请执行以下操作(在大多数情况下,实现评论者所说的(:
托管表单的XAML代码
<AControl:UserControl1 x:Name="cboBob" HorizontalAlignment="Left" Margin="100,118,0,0" VerticalAlignment="Top" Width="200" Height="29" SelectedColor="{Binding Path=BeSelected, RelativeSource={RelativeSource AncestorType=Window}}}"/>
模式并不重要,因为MainWindow既不实现INPC,也不知道((viewModelBinding(DataContext(.Selected(因此,BeSelected(何时更改。事实上,正如乔所说,OneWayToSource不起作用。。。RelativeSource是必需的,因为BeSelected是MainWindow的属性,而不是MainWindow的DataContext。
型号主
modelMain需要实现IEquatable(就像Janne评论的那样(。为什么?因为BeSelected=new modelMain(…(创建了一个新的modelMain,它不是组合框的ItemsSource(ColorList(中的项之一。新对象可能与其中一个项具有相同的属性值,但这并不能使它们相等(不同的对象=内存中的不同地址(。IEquatable让你有机会超越它。
public class modelMain : ViewModelBase, IEquatable<modelMain>
{
...
public bool Equals(modelMain other)
{
return (HexValue == other.HexValue);
}
}
viewModelMain的ColorList的setter正在调用属性名称为"Colors"的SetProperty,而它应该是"ColorsList"。它没有被使用,所以它不会阻止你的例子发挥作用,但它仍然是错误的。