我想我对WPF数据绑定的机制有点迷恋。到目前为止,我一直这样认为:数据绑定的任何目标都必须是依赖性保留考虑到这一点,我设计了一个非常简单的基于按钮的用户控件,如下所示(归结为最必要的部分):
<Button x:Class="MyNamespace.IconButton"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image x:Name="imIcon"
Source="{Binding Path=ImageSource}"
Grid.Column="0"
Width="16" Height="16"
Margin="0,0,5,0"/>
<TextBlock x:Name="tbText" Text="{Binding Path=Text}" Grid.Column="1"/>
</Grid>
</Button>
C级#
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace MyNamespace
{
public partial class IconButton : Button
{
public string Text
{
get { return this.tbText.Text; }
set { this.tbText.Text = value; }
}
public ImageSource ImageSource
{
get
{
return (ImageSource)GetValue(ImageSourceProperty);
}
set
{
SetValue(ImageSourceProperty, value);
}
}
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource",typeof(ImageSource), typeof(IconButton));
public IconButton()
{
InitializeComponent();
}
}
}
使用此控件非常简单:
<v:IconButton Margin="5,0,0,0" Height="24" Width="100"
Text="reload"
ImageSource="..\Resources\images\refresh.png"/>
VisualStudio设计器显示按钮和文本,但拒绝计算依赖项属性“ImageSourceProperty”。当我将“Text”实现为dependencProperty时也会发生同样的情况。为什么会这样?
还有,为什么我需要一个常规的“图像源”?如果我从代码中删除此属性,VS XAML编辑器(在其中使用控件)将向ImageSource属性提示“System.Windows.DependencyProperty属性MyNamespace.IconButton.ImageSourceProperty属性“(而不是常规的属性描述),这意味着它可以正确解析依赖性属性,然而,我不能这样设置任何值(“附加属性没有setter”)。为什么我只能通过xaml中的常规属性来设置dependecy属性的值?
最后,我还有一个问题。为了简化解释,我在本例中使用了一个文章类别设置。用户界面应该允许用户重新分类商店文章。
<ListView x:Name="lvArticles"
ItemsSource="{Binding Path=Articles}"
IsSynchronizedWithCurrentItem="True"/>
<ComboBox IsSynchronizedWithCurrentItem="True"
x:Name="cbCategories"
ItemsSource="{Binding Path=Categories}"
SelectedItem="{Binding Path=Articles.CurrentItem.Category, Mode=TwoWay}"/>
我可以通过在cbCategories中进行选择来更改文章(即设置新类别),但是从lvArticles中选择文章时,cbCategories不会自动设置为相关类别。我所做的有什么问题吗?或者这是另一个WPF异常?
提前谢谢你的任何提示。。。
从昨天开始,除了这种奇怪的组合框行为,我什么都没想过。我在代码中发现的第一个缺陷是缺少对
Equals
方法。结果,任何东西都不可能是SelectedItem—所有ItemSource元素与SelectedItem的比较都会导致一个整洁的“False”。我现在把这个补好了。但是在我的主详细信息视图中,在更改所选主记录时,详细信息仍然不会捕捉到正确的值。
又是一次编辑
为了弥补这一点,我创建了一个非常丑陋的事件驱动解决方案。
<ListView x:Name="lvArticles"
ItemsSource="{Binding Path=Articles}"
IsSynchronizedWithCurrentItem="True"
SelectionChanged="LvArticlesSelectionChanged"/>
private void LvArticlesSelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ArticleViewModel avm = this.Articles.SelectedItem as ArticleViewModel;
foreach (CategoryViewModel cvm in this.ViewModel.Categories)
{
if( cvm.Equals( avm.Category ) )
{
this.cbCategories.SelectedItem = cvm;
}
}
}
这是我能想象到的最丑陋的解决方案-我们有绑定做什么?但既然我要送,我会一直送下去直到有人给我一个很好的解释。。。