C#VS:将代码分解到UserControl中,使用ObservableCollection,并使用Binding使用它

本文关键字:使用 ObservableCollection Binding 代码 分解 UserControl C#VS | 更新日期: 2023-09-27 18:00:51

我正在将一些代码分解到UserControls中,这些参数在使用时会被绑定。我在使用ObservableCollection作为DependencyProperty时遇到了困难。

显示困难的例子是一个包含两个DependencyProperty:的主窗口中的项目

  1. 一个表示字符串(名为"Data"(,以及
  2. 另一个代表ObservableCollection(名为"Origin"(

以及一个UserControl(名为UserControl1(,它暴露了两个类似的DependencyProperty(分别名为"Liste"answers"Noun"(。

主窗口包含一个文本块(Text绑定到"Data"(和一个组合框(ItemsSource绑定到"Origin"(。两个都工作得很好。这两个控件都被分解到UserControl1中,DependencyProperty"Liste"answers"Noun"充当中间控件,UserControl1在MainWindow中使用。

(MainWindow和UserControl1的(每个DataContext都设置为"this"。

问题是,当分解后的TextBlock(在UserControl1中(工作并显示"数据"的内容时,分解后的ComboBox不工作,其DropDown为空。

MainWindow.xaml的代码是:

<Window x:Class="ChainedBindingUserControl.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow"
    Height="350" Width="525"
    xmlns:Local="clr-namespace:ChainedBindingUserControl"
    >
    <StackPanel>
        <TextBlock Text="{Binding Data}"
                   Width="150"
                   />
        <ComboBox ItemsSource="{Binding Origin}"
                   Width="150"
                  />
        <Label Content="--------------------------------------------------"
               Width="200"
              />
        <Local:UserControl1 Liste="{Binding Origin}"
                            Noun="{Binding Data}"
                            Height="50" Width="150"
                            />
    </StackPanel>
</Window>

它背后的代码是:

namespace ChainedBindingUserControl
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<String> Origin
        {
            get { return (ObservableCollection<String>)GetValue(OriginProperty); }
            set { SetValue(OriginProperty, value); }
        }
        public static readonly DependencyProperty OriginProperty =
            DependencyProperty.Register("Origin", typeof(ObservableCollection<String>), typeof(MainWindow),
                    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
        public String Data
        {
            get { return (String)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(String), typeof(UserControl1),
                    new FrameworkPropertyMetadata("Blablabla", FrameworkPropertyMetadataOptions.AffectsRender));

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;
            ObservableCollection<String> zog = new ObservableCollection<String>();
            zog.Add("A");
            zog.Add("B");
            zog.Add("C");
            Origin = zog;
        }
    }
}

文件UserControl1.xaml是:

<UserControl x:Class="ChainedBindingUserControl.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"
             Name="root"
             d:DesignHeight="300" d:DesignWidth="300">
    <StackPanel>
        <TextBlock Text="{Binding Noun}"
                   />
        <ComboBox ItemsSource="{Binding Liste}"
                  />
    </StackPanel>
</UserControl>

它背后的代码是:

namespace ChainedBindingUserControl
{
    public partial class UserControl1 : UserControl
    {
        public ObservableCollection<String> Liste
        {
            get { return (ObservableCollection<String>)GetValue(ListeProperty); }
            set { SetValue(ListeProperty, value); }
        }
        public static readonly DependencyProperty ListeProperty =
            DependencyProperty.Register("Liste", typeof(ObservableCollection<String>), typeof(UserControl1),
                    new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsRender));
        public String Noun
        {
            get { return (String)GetValue(NounProperty); }
            set { SetValue(NounProperty, value); }
        }
        public static readonly DependencyProperty NounProperty =
            DependencyProperty.Register("Noun", typeof(String), typeof(UserControl1),
                    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender));

        public UserControl1()
        {
            InitializeComponent();
            this.DataContext = this;
        }
    }
}

`

编辑

根据上提供的信息和片段http://sshumakov.com/2012/11/13/how-to-create-dependency-properties-for-collections/,我把UserControl1后面的代码改成了

    public partial class UserControl1 : UserControl
    {
        public IList Liste
        {
            get { return (List<String>)GetValue(ListeProperty); }
            set { SetValue(ListeProperty, value); }
        }
        public static readonly DependencyProperty ListeProperty =
            DependencyProperty.Register("Liste", typeof(IList), typeof(UserControl1),
                    new FrameworkPropertyMetadata(new List<String>(), FrameworkPropertyMetadataOptions.AffectsRender));
        public String Noun
        {
            get { return (String)GetValue(NounProperty); }
            set { SetValue(NounProperty, value); }
        }
        public static readonly DependencyProperty NounProperty =
            DependencyProperty.Register("Noun", typeof(String), typeof(UserControl1),
                    new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsRender));

        public UserControl1()
        {
            InitializeComponent();
            this.DataContext = this;
            SetValue(ListeProperty, new List<String>());
        }
    }

但它仍然不起作用。

问题不是来自DataContext,因为TextBlock按预期工作。

这里的问题是具体的:为什么当属性的类型为String时,充当Binding中间体的DependencyProperty可以工作,而当它的类型为ObservableCollection(或List等(时,它不工作。

提前感谢您的解释。

C#VS:将代码分解到UserControl中,使用ObservableCollection,并使用Binding使用它

您的问题出现在UserControl的xaml中,这里是:

<TextBlock Text="{Binding Noun}"
           />
<ComboBox ItemsSource="{Binding Liste}"
          />

这些绑定表达式试图在UserControl的DataContext上定位Noun和Liste属性,而不是在UserControl本身上。您需要指定一个不同的目标。由于您已经命名了UserControl元素,因此可以将绑定替换为:

<TextBlock Text="{Binding ElementName=root, Path=Noun}"
           />
<ComboBox ItemsSource="{Binding ElementName=root, Path=Liste}"
          />

想象一下,您正在创建具有接受集合的属性的控件:

 public class CustomControl : Control
 { 
 public IEnumerable<string> Items { get; set; } 
 }

如果您希望属性Items充当绑定目标,则必须将其更改为依赖属性:

public class CustomControl : Control
{
 public static readonly DependencyProperty ItemsProperty = 
             DependencyProperty.Register("Items", typeof(IEnumerable<string>), typeof (CustomControl), new PropertyMetadata(new List<string>())); 
     public IEnumerable<string> Items 
     { 
         get { return (IEnumerable<string>) GetValue(ItemsProperty); } 
         set { SetValue(ItemsProperty, value); } 
     } 
}

正如您所看到的,我们将此属性更改为依赖属性,并提供List类的新实例作为默认参数。事实证明,这个默认值将在类级别上使用(即,它将只创建一次,并且CustomControl的每个实例都将引用同一个集合(。因此,我们需要一个修改:

public class CustomControl : Control
 {
     public CustomControl() 
     {
        Items = new List<string>(); 
     }
 }

现在您可以使用此控件并通过绑定为Items属性提供值:

<Grid> 
 <DependencyPropertiesCollection:CustomControl Items="{Binding   ItemsSource}"/> 
</Grid>

目前,此控件有一个限制-Items属性不能像以下代码那样直接在XAML中填充:

<Grid>
   <DependencyPropertiesCollection:CustomControl> 
       <DependencyPropertiesCollection:CustomControl.Items> 
          <System:String>Item 1</System:String> 
          <System:String>Item 2</System:String> 
          <System:String>Item 3</System:String> 
          <System:String>Item 4</System:String> 
          <System:String>Item 5</System:String>
       </DependencyPropertiesCollection:CustomControl.Items>
  </DependencyPropertiesCollection:CustomControl> 
 </Grid>

要解决此问题,您需要将属性类型从IEnumerable更改为IList:

public class CustomControl : Control  
{ 
      public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register("Items", typeof (IList), typeof (CustomControl), new PropertyMetadata(new List<string>())); 
  public IList Items 
  { 
       get { return (IList)GetValue(ItemsProperty); } 
       set { SetValue(ItemsProperty, value); }
  } 
  public CustomControl() 
  {
        Items = new List<string>(); 
  } 
 }

学分:-http://sshumakov.com/2012/11/13/how-to-create-dependency-properties-for-collections/