如何在用户控件中使用数据绑定(在页面中有效但在用户控件中无效)

huangapple go评论75阅读模式
英文:

How to use DataBindings in UserControls (works in page but not in uc)

问题

以下是翻译好的部分:

现在,我基本上只是复制了逻辑。我在一个名为“Components”的子文件夹中创建了一个新的UserControl:

XAML

<UserControl x:Class="WpfApp1.Components.ExampleComponent"
             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" 
             xmlns:local="clr-namespace:WpfApp1.Components"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <ListView ItemsSource="{Binding OtherItems}" />
    </Grid>
</UserControl>

C#

using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace WpfApp1.Components
{    
    public partial class ExampleComponent : UserControl
    {
        private ObservableCollection<string> _otherItems;

        public ObservableCollection<string> OtherItems
        {
            get { return _otherItems; }
            set { _otherItems = value; }
        }

        public ExampleComponent()
        {
            _otherItems = new ObservableCollection<string>();
            InitializeComponent();

            OtherItems.Add("Other 1");
            OtherItems.Add("Other 2");
        }
    }
}

然后,我将以下行添加到主窗口的StackPanel中:

<Components:ExampleComponent />

以及

xmlns:Components="clr-namespace:WpfApp1.Components"

作为额外的Window属性。

我现在得到的是第一个ListView和第二个空的 ListView

我想了解为什么这不起作用,以及如何修复它。

英文:

There are several questions about this but I understand too little about the subject to understand what I am missing.

It's my first time working in WPF and I want to create several submodules (what are called UserControls I believe) to make the XAML easier to read and keep everything as its own part and potentially reusable.

I followed a YouTube video online to get the following code working:

XAML

&lt;Window x:Class=&quot;WpfApp1.MainWindow&quot;
        xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
        xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
        xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
        xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
        xmlns:local=&quot;clr-namespace:WpfApp1&quot;
        mc:Ignorable=&quot;d&quot;
        Title=&quot;MainWindow&quot; Height=&quot;450&quot; Width=&quot;800&quot;&gt;
    &lt;StackPanel&gt;
        &lt;ListView ItemsSource=&quot;{Binding Items}&quot; /&gt;
    &lt;/StackPanel&gt;
&lt;/Window&gt;

Code Behind

using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApp1
{    
    public partial class MainWindow : Window
    {
        private ObservableCollection&lt;string&gt; _items;
        public ObservableCollection&lt;string&gt; Items
        {
            get { return _items; }
            set { _items = value; }
        }
        public MainWindow()
        {
            DataContext = this;
            _items = new ObservableCollection&lt;string&gt;();
            InitializeComponent();
            Items.Add(&quot;Item 1&quot;);
            Items.Add(&quot;Item 2&quot;);
        }
    }
}

Which correctly renders a ListView with the two items.

Now I basically just copied the logic. I created a new UserControl in a subfolder "Components":

XAML

&lt;UserControl x:Class=&quot;WpfApp1.Components.ExampleComponent&quot;
             xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
             xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
             xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot; 
             xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot; 
             xmlns:local=&quot;clr-namespace:WpfApp1.Components&quot;
             mc:Ignorable=&quot;d&quot; 
             d:DesignHeight=&quot;450&quot; d:DesignWidth=&quot;800&quot;&gt;
    &lt;Grid&gt;
        &lt;ListView ItemsSource=&quot;{Binding OtherItems}&quot; /&gt;
    &lt;/Grid&gt;
&lt;/UserControl&gt;
using System.Collections.ObjectModel;
using System.Windows.Controls;

namespace WpfApp1.Components
{    
    public partial class ExampleComponent : UserControl
    {
        private ObservableCollection&lt;string&gt; _otherItems;

        public ObservableCollection&lt;string&gt; OtherItems
        {
            get { return _otherItems; }
            set { _otherItems = value; }
        }

        public ExampleComponent()
        {
            _otherItems = new ObservableCollection&lt;string&gt;();
            InitializeComponent();

            OtherItems.Add(&quot;Other 1&quot;);
            OtherItems.Add(&quot;Other 2&quot;);
        }
    }
}

Then I added the following line into the main window's StackPanel:

&lt;Components:ExampleComponent /&gt;

and

 xmlns:Components=&quot;clr-namespace:WpfApp1.Components&quot;

as an additional Window property.

What I get now is the first ListView and a second empty one below it.

I'd like to understand why this doesn't work, and how I can fix it.

答案1

得分: 3

你忘记设置UserControlDataContext

public ExampleComponent()
{
    _otherItems = new ObservableCollection<string>();
    InitializeComponent();
    DataContext = this; //&lt;--

    OtherItems.Add("Other 1");
    OtherItems.Add("Other 2");
}

请注意,UserControl通常应该从其父元素继承DataContext

然后,您可以直接绑定到父窗口的Items集合:

<ListView ItemsSource="{Binding Items}" />

而不是设置UserControlDataContext属性并断开继承链,您可以使用RelativeSource将绑定到UserControl本身的特定属性:

<ListView ItemsSource="{Binding OtherItems,
    RelativeSource={RelativeSource AncestorType=UserControl}}" />
英文:

You forgot to set the DataContext of the UserControl:

public ExampleComponent()
{
    _otherItems = new ObservableCollection&lt;string&gt;();
    InitializeComponent();
    DataContext = this; //&lt;--

    OtherItems.Add(&quot;Other 1&quot;);
    OtherItems.Add(&quot;Other 2&quot;);
}

Note that a UserControl should generally speaking inherit the DataContext from its parent element.

You can then bind directly to the Items collection of the parent window:

&lt;ListView ItemsSource=&quot;{Binding Items}&quot; /&gt;

Instead of setting the DataContext property of the UserControl and break the inheritance chain, you could bind to a specific property of the UserControl itself using a RelativeSource:

&lt;ListView ItemsSource=&quot;{Binding OtherItems,
    RelativeSource={RelativeSource AncestorType=UserControl}}&quot; /&gt;

huangapple
  • 本文由 发表于 2023年6月5日 23:11:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/76407799.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定