代码之家  ›  专栏  ›  技术社区  ›  Sebastian Edelmeier

WPF用户控件和数据绑定

  •  1
  • Sebastian Edelmeier  · 技术社区  · 15 年前

    我想我对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;
                }
            }
        }
    

    这是我能想象到的最丑陋的解决方案-我们有绑定做什么?但既然我要送,我会一直送下去直到有人给我一个很好的解释。。。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Arcturus    15 年前

    将数据源绑定到按钮,而不是图标按钮:

    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    

    两种选择:

    选项1[更改相对资源绑定]:

    最简单的解决方案:

    更改数据源以找到正确的父级。

    DataContext="{Binding RelativeSource={RelativeSource FindAncestor, 
                         AncestorType={x:Type MyNamespace:IconButton}}}"
    

    选项2[模板绑定]:

    ControlTemplate ,所以您可以使用 TemplateBindings 在要从父控件接管的属性上:

    <Button x:Class="MyNamespace.IconButton">
      <Button.Template>
          <ControlTemplate TargetType="MyNamespace:IconButton">
              <Grid>
            ...
            <Image x:Name="imIcon"
                   Source="{TemplateBinding ImageSource}" 
                   Grid.Column="0" 
                   Width="16" Height="16"
                   Margin="0,0,5,0"/>
            <TextBlock x:Name="tbText" Text="{TemplateBinding Text}" Grid.Column="1"/>
              </Grid>
          </ControlTemplate>
      <Button.Template>
    </Button>
    
    推荐文章