为什么这个简单的数据绑定场景不起作用? (组合框相关)

发布于 2024-07-12 06:47:03 字数 3403 浏览 4 评论 0原文

我已经在这个问题上摸不着头脑有一段时间了,现在很困惑。

问题场景更容易用代码来解释,所以希望它能说明一切。 首先,我有一个 silverlight 应用程序,其 XAML 中有以下内容...

<UserControl x:Class="SilverlightApplication2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Width="400" Height="300">

<UserControl.Resources>
    <DataTemplate x:Key="icTemplate">
        <ComboBox ItemsSource="{Binding StringsChild}" SelectedItem="{Binding SelectedItem}"/>
    </DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ItemsControl x:Name="ic" ItemTemplate="{StaticResource icTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

    <Button Click="Save" Grid.Row="1" Content="GO"/>
</Grid>

我的代码隐藏看起来像这样...(全部写在一个类文件中,以便您可以轻松地将其复制到您自己的项目中并编译)

namespace SilverlightApplication2
{
    public partial class Page : UserControl
    {
        public ObservableCollection<SomeClass> StringsParent { get; set; } 

        public Page()
        {   
            InitializeComponent();
            StringsParent = new ObservableCollection<SomeClass>();
            ic.ItemsSource = StringsParent;
        }

        private void Save(object sender, RoutedEventArgs e)
        {
            SomeClass c = new SomeClass();
            c.StringsChild.Add("First");
            c.StringsChild.Add("Second");
            c.StringsChild.SetSelectedItem("Second");
            StringsParent.Add(c);
        }
    }

    public class SomeClass
    {
        public SelectableObservablecollection<string> StringsChild { get; set; }

        public SomeClass()
        {
            StringsChild = new SelectableObservablecollection<string>();
        }    
    }

    public class SelectableObservablecollection<T> : ObservableCollection<T>
    {
        public SelectableObservablecollection()
            : base()
        {

        }

        public void SetSelectedItem<Q>(Q selectedItem)
        {
            foreach (T item in this)
            {
                if (item.Equals(selectedItem))
                {
                    SelectedItem = item;
                    return;
                }
            }
        }

        private T _selectedItem;
        public T SelectedItem
        {
            get
            {
                return _selectedItem;
            }
            set
            {
                _selectedItem = value;
                OnPropertyChanged(new PropertyChangedEventArgs("SelectedItem"));
            }
        }
    }
}

所以让我解释一下... 我开始编写一种创建 ObservableCollection 的通用方法,该集合具有 SelectedItem 属性,这样当我将集合绑定到 ComboBox 时,我可以绑定 ComboBox 的 SelectedItem强> 财产给它。

但是,由于某种原因,当 ComboBox 通过 ItemTemplate 有效嵌套时,它似乎不起作用。 我实际上有一个列表列表,这个场景非常简单,以至于我不知道出了什么问题。

当您运行代码时,您将看到模板化的 ComboBox 确实拾取了正确的项目,但尽管有绑定,但它从未设置为 SelectedItem。

我知道这有点啰嗦,但是……有什么想法吗?

多谢

I've been scratching my head on this one for a while now and am stumped at the moment.

The problem scenario is easier to explain as code so hopefully it speaks for itself. First of all, I have a silverlight application with the following in the XAML...

<UserControl x:Class="SilverlightApplication2.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
Width="400" Height="300">

<UserControl.Resources>
    <DataTemplate x:Key="icTemplate">
        <ComboBox ItemsSource="{Binding StringsChild}" SelectedItem="{Binding SelectedItem}"/>
    </DataTemplate>
</UserControl.Resources>

<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <ItemsControl x:Name="ic" ItemTemplate="{StaticResource icTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical"/>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

    <Button Click="Save" Grid.Row="1" Content="GO"/>
</Grid>

My code-behind looks like this...(all written in a single class file so that it's easy for you to copy it into your own project and compile)

namespace SilverlightApplication2
{
    public partial class Page : UserControl
    {
        public ObservableCollection<SomeClass> StringsParent { get; set; } 

        public Page()
        {   
            InitializeComponent();
            StringsParent = new ObservableCollection<SomeClass>();
            ic.ItemsSource = StringsParent;
        }

        private void Save(object sender, RoutedEventArgs e)
        {
            SomeClass c = new SomeClass();
            c.StringsChild.Add("First");
            c.StringsChild.Add("Second");
            c.StringsChild.SetSelectedItem("Second");
            StringsParent.Add(c);
        }
    }

    public class SomeClass
    {
        public SelectableObservablecollection<string> StringsChild { get; set; }

        public SomeClass()
        {
            StringsChild = new SelectableObservablecollection<string>();
        }    
    }

    public class SelectableObservablecollection<T> : ObservableCollection<T>
    {
        public SelectableObservablecollection()
            : base()
        {

        }

        public void SetSelectedItem<Q>(Q selectedItem)
        {
            foreach (T item in this)
            {
                if (item.Equals(selectedItem))
                {
                    SelectedItem = item;
                    return;
                }
            }
        }

        private T _selectedItem;
        public T SelectedItem
        {
            get
            {
                return _selectedItem;
            }
            set
            {
                _selectedItem = value;
                OnPropertyChanged(new PropertyChangedEventArgs("SelectedItem"));
            }
        }
    }
}

So let me explain...
I set out to write a generic way of creating an ObservableCollection that has a SelectedItem property on it so that when I bind the collection to a ComboBox for example, I can Bind the ComboBox's SelectedItem property to it.

However, for some reason, it does not seem to work when the ComboBox is effectively nested via an ItemTemplate. I effectively have a list of lists, a scenario which is simple enough that I'm lost as to what's wrong.

When you run the code you'll see that the templated ComboBox does pick up the correct items, but it's never set to a SelectedItem despite the binding.

I know it's rather long winded, but...any ideas?

Thanks alot

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

揪着可爱 2024-07-19 06:47:03

调试器输出实际上为您提供了问题的提示:

System.Windows.Data Error: BindingExpression path error: 'SelectedItem' property not find on 'ExpressionElements.SomeClass' 'ExpressionElements.SomeClass' (HashCode= 49044892)。 BindingExpression: Path='SelectedItem' DataItem='ExpressionElements.SomeClass' (HashCode=49044892); 目标元素是“System.Windows.Controls.ComboBox”(名称=“”); 目标属性是“SelectedItem”(类型“System.Object”)。

由于模板的数据上下文是 SomeClass 类的实例,因此您所要做的就是将 SelectedItem 绑定从 SelectedItem 更改为 StringsChild.SelectedItem

<DataTemplate x:Key="icTemplate">
    <ComboBox ItemsSource="{Binding StringsChild}" 
     SelectedItem="{Binding StringsChild.SelectedItem}"/>
</DataTemplate>

The debugger output actually gives you a hint to the problem:

System.Windows.Data Error: BindingExpression path error: 'SelectedItem' property not found on 'ExpressionElements.SomeClass' 'ExpressionElements.SomeClass' (HashCode=49044892). BindingExpression: Path='SelectedItem' DataItem='ExpressionElements.SomeClass' (HashCode=49044892); target element is 'System.Windows.Controls.ComboBox' (Name=''); target property is 'SelectedItem' (type 'System.Object')..

Because the Data context for the template is an instance of the SomeClass class, all you have to do is change the SelectedItem binding from SelectedItem to StringsChild.SelectedItem:

<DataTemplate x:Key="icTemplate">
    <ComboBox ItemsSource="{Binding StringsChild}" 
     SelectedItem="{Binding StringsChild.SelectedItem}"/>
</DataTemplate>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文