C#VS:使用ObservableCollection将代码保存到UserControl中,并使用Binding消耗它

时间:2015-07-01 16:53:31

标签: c# wpf xaml user-controls

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

显示难度的示例是一个包含两个DependencyProperty的MainWindow项目:

  1. 一个表示字符串(名为"数据")和
  2. 另一个代表ObservableCollection(名为" Origin");
  3. 和一个UserControl(名为UserControl1),暴露两个相似的DependencyProperty(名为resp。" Liste"" Noun")。

    MainWindow包含一个TextBlock,Text绑定到" Data"以及ItemsSource绑定的ComboBox" Origin"。两者都很好。 使用DependencyProperty" Liste"将两个控件都考虑在UserControl1中。和#34;名词"作为中间人,在MainWindow中使用UserControl1。

    每个DataContext(MainWindow和UserControl1)都设置为"这个"。

    麻烦的是,当因子TextBlock(在UserControl1中)工作并显示" Data"的内容时,因子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>());
            }
        }
    

    但它仍无效。

    由于TextBlock按预期工作,故障并非来自DataContext。

    这里的麻烦是具体的:为什么当属性是String类型时,作为Binding的中间件的DependecyProperty工作,而当它是ObservableCollection(或List等)类型时它不起作用。

    提前感谢您的任何解释。

2 个答案:

答案 0 :(得分:0)

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

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

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

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>

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

<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/

答案 1 :(得分:0)

您的问题出现在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}"
          />