简体   繁体   English

C#WPF数据绑定“找不到属性”

[英]C# WPF DataBinding “Can't find Property”

I'm still trying to get my head around databinding in WPF and so I'm having a bit of a problem working out how to solve this issue for the past 10 hours: 我仍在努力解决WPF中的数据绑定问题,因此在解决过去10个小时如何解决此问题时遇到了一些问题:

I have an object named birdList which consist of a list of Bird Objects(bird1 and bird2). 我有一个名为birdList的对象,其中包含Bird对象(bird1和bird2)的列表。 I have made all properties within the objects public. 我已经公开了对象中的所有属性。 When I try to data bind the Common_Name property to a TextBlock I get nothing. 当我尝试将Common_Name属性绑定到TextBlock时,我什么也没得到。 Looking at the output in Visual Studio I see the following Errors/Warnings: 在Visual Studio中查看输出,我看到以下错误/警告:

System.Windows.Data Warning: 60 : BindingExpression (hash=47755470): Default mode resolved to OneWay
System.Windows.Data Warning: 78 : BindingExpression (hash=47755470): Activate with root item 'birdList'
System.Windows.Data Warning: 108 : BindingExpression (hash=47755470):   At level 0 - for String.Bird found accessor <null>
System.Windows.Data Warning: 108 : BindingExpression (hash=47755470):   At level 0 - for EnumerableCollectionView.Bird found accessor <null>
System.Windows.Data Warning: 108 : BindingExpression (hash=47755470):   At level 0 - for Char.Bird found accessor <null>

System.Windows.Data Error: 40 : BindingExpression path error: 'Bird' property not found on 'object' ''String' (HashCode=-874795121)'.

System.Windows.Data Warning: 103 : BindingExpression (hash=47755470): Replace item at level 1 with {NullDataItem}
System.Windows.Data Warning: 88 : BindingExpression (hash=47755470): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=47755470): TransferValue - using final value ''

C# Code: C#代码:

    public Birds birdList { get; set; }

    Bird bird1 { get; set; }
    Bird bird2 { get; set; }

public MainWindow()
    {

        InitializeComponent();

        birdList = new Birds();

        bird1 = new Bird();
        bird2 = new Bird();

        bird1.Common_Name = "Mallard";
        bird2.Common_Name = "Red-winged Blackbird";

        birdList.Bird.Add(bird1);
        birdList.Bird.Add(bird2);

        birdList.Test = "Testing!";

        this.DataContext = this;

        this.Photos = (PhotoCollection)(Application.Current.FindResource("Photos") as ObjectDataProvider).Data;
        this.Photos.Path = "E:\\Network Drive\\SarDonnie's Documents - Networked\\Birds\\Ducks, Geese, and Swans (Anatidae)\\Mallard\\Clear Lake Bay Park 1-18-16";

    }

public class Birds
{
    public string Test { get; set; }

    public List<Bird> _Birds = new List<Bird>();
    public List<Bird> Bird
    {
        get
        {
            return this._Birds;
        }
    }
}

public class Bird
{

    public string Common_Name { get; set; }

} 

XMAL: XMAL:

        <Grid  Grid.Column="2">
            <ContentControl Content="birdList">
                <ContentControl.ContentTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Height="50" Text="{Binding Bird.Common_Name,diag:PresentationTraceSources.TraceLevel=High}">
                            </TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ContentControl.ContentTemplate>
            </ContentControl>
        </Grid>

I have also tried this to test accessing the Test property inside the birdList Object: 我也尝试过此方法来测试访问birdList对象内部的Test属性:

<Grid  Grid.Column="2">
            <ContentControl Content="birdList">
                <ContentControl.ContentTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Height="50" Text="{Binding Test>
                            </TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ContentControl.ContentTemplate>
            </ContentControl>
        </Grid>

My question is why can't I seem to find the birdList.Bird.Common_Name property or the birdList.Test property? 我的问题是为什么我似乎无法找到birdList.Bird.Common_Name属性或birdList.Test属性?

Thanks! 谢谢!

Also feel free to point me to some good sites that house information on WPF. 也可以随时将我指向一些包含WPF信息的优秀站点。 I hate banging my head on this keyboard and getting no where! 我讨厌用这个键盘敲打头,却一无所获!

Your code has two problems: 您的代码有两个问题:

  1. You need to tell the path of the "list" to xaml (via "ItemsSource" property). 您需要(通过“ ItemsSource”属性)告诉“列表”到xaml的路径。
  2. Use controls that accept collections such as ListBox. 使用接受集合的控件,例如ListBox。

Here's my code: 这是我的代码:

  • MainWindow.xaml.cs MainWindow.xaml.cs
public partial class MainWindow : Window
{
    public List<Bird> Birds { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        Birds = new List<Bird>();

        var bird1 = new Bird();
        bird1.CommonName = "Mallard";
        Birds.Add(bird1);

        var bird2 = new Bird();
        bird2.CommonName = "Red-winged Blackbird";
        Birds.Add(bird2);

        this.DataContext = this;
    }

    public class Bird
    {
        public string CommonName { get; set; }
    }
}
  • MainWindow.xaml MainWindow.xaml
<Grid>
    <ListBox ItemsSource="{Binding Birds}" DisplayMemberPath="CommonName" />
</Grid>

EDIT 编辑

If you need to update from the code on runtime, follow Jai's advice. 如果您需要在运行时从代码进行更新,请遵循Jai的建议。 I only showed the minimal solution for the question. 我只显示了该问题的最小解决方案。

EDIT2 编辑2

Always remember to use properties in binding, or else it won't work. 始终记住在绑定中使用属性 ,否则它将无法正常工作。

public class Birds
{
    public string Test { get; set; }

    //Binding source must be a property!!
    public List<Bird> _Birds { get; set; } = new List<Bird>();
    public List<Bird> Bird
    {
        get
        {
            return this._Birds;
        }
    }
}
<Grid>
    <DataGrid ItemsSource="{Binding birdList._Birds}" />
</Grid>

Okay, there are quite a bit of problem out there. 好的,那里有很多问题。

Firstly, you have a list of birds, but you only have one TextBlock to display it. 首先,您有一个鸟类列表,但是只有一个TextBlock可以显示它。 If you have manually made multiple TextBlock (which you didn't show us), then there is no point to make a list of birds, because it means that your view is aware exactly how many birds there are (in your viewmodel???). 如果您手动制作了多个TextBlock (未显示给我们),那么就没有必要列出鸟的列表,因为这意味着您的视图确切知道有多少鸟(在您的视图模型中? )。 Therefore, Doncot is right to say that you should use a ListBox , or any other controls that allow you to display a list of items. 因此,Doncot正确地说您应该使用ListBox或任何其他允许您显示项目列表的控件。

Secondly, if you want to use a ListBox (or something similar), you would need to have to consider your list of birds. 其次,如果要使用ListBox (或类似的东西),则需要考虑鸟类列表。 Binding is always related to INotifyPropetyChanged , INotifyCollectionChanged and DependencyProperty . 绑定始终与INotifyPropetyChangedINotifyCollectionChangedDependencyProperty Creating a class just to hold your list does not seem necessary, unless you have other special requirements that we are not aware of. 除非您有我们不知道的其他特殊要求,否则似乎不必创建仅用于保存列表的类。

Doncot is quite near there, but I want to touch a little more. 唐科特(Doncot)就在附近,但我想多谈一点。 Using a List<Bird> works fine, except that your ListBox would not know it needs to update itself when the list is modified later. 使用List<Bird>可以很好地工作,除了在以后修改列表时, ListBox不知道需要更新自身。 This is because that List<Bird> does not notify the Binding engine when a change occurs. 这是因为发生更改时List<Bird>不会通知绑定引擎。

If you implement this together with INotifyPropertyChanged , your binding would be able to trigger when the whole List<Bird> is being re-instantiated (ie Birds = new List<Bird>(); ). 如果将其与INotifyPropertyChanged一起实现,则可以在重新实例化整个List<Bird>时触发绑定(即Birds = new List<Bird>(); )。 This is normally not what you want, either. 这通常也不是您想要的。

If you change the whole List<Bird> into ObservableCollection<Bird> , your binding will trigger when you do Birds.Add(new Bird()); 如果将整个List<Bird>更改为ObservableCollection<Bird> ,则在执行Birds.Add(new Bird());时将触发绑定Birds.Add(new Bird()); . This is because ObservableCollection<> is an implementation of INotifyCollectionChanged interface, which you may also choose to implement it on your own. 这是因为ObservableCollection<>INotifyCollectionChanged接口的实现,您也可以选择自行实现。 Up to this point, your binding is pretty solid, except that it does not know when a Bird within that list is being modified. 到目前为止,您的绑定非常牢固,只是它不知道何时修改该列表中的Bird

Consider this: 考虑一下:

Birds.ElementAt(0).Common_Name = "New Bird Name!";

The collection itself is not being modified, because it is still holding to the reference of the same Bird instance. 集合本身并未被修改,因为它仍保留着同一Bird实例的引用。 Therefore, the Binding engine will not be aware of this change. 因此,绑定引擎将不会意识到此更改。 To solve this, your Bird class needs to implement INotifyPropertyChanged as well, which is similar to what vishakh369 answered. 为了解决这个问题,您的Bird类也需要实现INotifyPropertyChanged ,这与vishakh369回答的类似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM