在自定义用户控件中绑定 ObservableCollection

发布于 2024-11-25 04:35:48 字数 3672 浏览 1 评论 0原文

我有一个在包含自定义类的用户控件中创建的 ObservableCollection。自定义类包含一些字符串和布尔值,没有什么特别的。

public class StringLineInfo : INotifyPropertyChanged
{
    private string name { set; get; }
    private Color color { set; get; }
    private bool visible { set; get; }
    private bool follow { set; get; }

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyPropertyChanged("Name");
        }
    }

    public Color Color
    {
        get { return color; }
        set
        {
            color = value;
            NotifyPropertyChanged("Color");
        }
    }

    public bool Visible
    {
        get { return visible; }
        set
        {
            visible = value;
            NotifyPropertyChanged("Visible");
        }
    }

    public bool Follow
    {
        get { return follow; }
        set
        {
            follow = value;
            NotifyPropertyChanged("Follow");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

在自定义控件的 Xaml 内,我添加了自定义图例控件。在自定义图例中,我有另一个 ObservableCollection,ItemsControl 与它进行数据绑定。

在 legend.xaml 中:

                                <!--<Image Name="imgMyImage" Grid.Column="1" Height="30" Width="30" Margin="5" Source="{Binding Name, Converter=NameToSrcConverter, ConverterParameter={StaticResource IconDictionary}}" />-->
                            <TextBlock Name="txtlineName" FontSize="12" Foreground="Black"  Text="{Binding Converter={StaticResource nameConverter}}"  Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

在 legend.xaml.cs 中:

    public ObservableCollection<StringLineInfo> allLines = new ObservableCollection<StringLineInfo>();

    public Dictionary<string, string> DvrIconDictionary = new Dictionary<string, string>();
    public Legend()
    {
        InitializeComponent();
        DataContext = this;
        itmCtrol.ItemsSource = allLines;
    }

    // to set the ItemsSource
    public void setItemsSource(ObservableCollection<StringLineInfo> source)
    {
        if (itmCtrl.ItemsSource == null)
        {
            itmCtrl.ItemsSource = source;
        }
    }

在主用户控件的构造函数中,我将图例中的 ObservableCollection 设置为等于主用户控件中的 ObservableCollection。

public MainControl()
    {
        InitializeComponent();
        MapLegend.SizeChanged += new SizeChangedEventHandler(MapLegend_SizeChanged);
        MapLegend.allLines = this.allLines;
    }

即使两个 ObservableCollections 始终包含相同的数据(它们现在是相同的对象),ItemsControl 也不会更新或显示任何内容。但是,如果我稍后在代码中将 ObservableCollections 设置为相等,例如单击按钮,那么它就可以正常工作。

该按钮仅调用“setItemsSource”函数。

关于为什么我不能在启动时将它们设置为相等的任何想法?

I have an ObservableCollection that is created in user control that contains a custom class. The custom class contains a few strings and booleans, nothing special.

public class StringLineInfo : INotifyPropertyChanged
{
    private string name { set; get; }
    private Color color { set; get; }
    private bool visible { set; get; }
    private bool follow { set; get; }

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyPropertyChanged("Name");
        }
    }

    public Color Color
    {
        get { return color; }
        set
        {
            color = value;
            NotifyPropertyChanged("Color");
        }
    }

    public bool Visible
    {
        get { return visible; }
        set
        {
            visible = value;
            NotifyPropertyChanged("Visible");
        }
    }

    public bool Follow
    {
        get { return follow; }
        set
        {
            follow = value;
            NotifyPropertyChanged("Follow");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this,
                new PropertyChangedEventArgs(propertyName));
        }
    }
}

Inside the Xaml of the custom control I have added custom legend control. Inside the custom legend I have another ObservableCollection that an ItemsControl is databound to.

In the legend.xaml:

                                <!--<Image Name="imgMyImage" Grid.Column="1" Height="30" Width="30" Margin="5" Source="{Binding Name, Converter=NameToSrcConverter, ConverterParameter={StaticResource IconDictionary}}" />-->
                            <TextBlock Name="txtlineName" FontSize="12" Foreground="Black"  Text="{Binding Converter={StaticResource nameConverter}}"  Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"/>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

In the legend.xaml.cs:

    public ObservableCollection<StringLineInfo> allLines = new ObservableCollection<StringLineInfo>();

    public Dictionary<string, string> DvrIconDictionary = new Dictionary<string, string>();
    public Legend()
    {
        InitializeComponent();
        DataContext = this;
        itmCtrol.ItemsSource = allLines;
    }

    // to set the ItemsSource
    public void setItemsSource(ObservableCollection<StringLineInfo> source)
    {
        if (itmCtrl.ItemsSource == null)
        {
            itmCtrl.ItemsSource = source;
        }
    }

In the constructor of the main user control I set the ObservableCollection from the legend equal to the ObservableCollection in the main user control.

public MainControl()
    {
        InitializeComponent();
        MapLegend.SizeChanged += new SizeChangedEventHandler(MapLegend_SizeChanged);
        MapLegend.allLines = this.allLines;
    }

Even though both ObservableCollections always contain the same data (they're now the same object) the ItemsControl will not update or show anything. HOWEVER, if I set the ObservableCollections equal later in the code, say a button click, then it works just fine.

The button just calls the "setItemsSource" function.

Any ideas on why I can't set them equal at startup?

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

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

发布评论

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

评论(1

╭ゆ眷念 2024-12-02 04:35:48

实际上,您拥有对尝试绑定到的 allLines 集合的三个引用。

  1. allLines 位于包含 MainControl 方法的类型中。
  2. legend.xaml.cs 中的 allLines。
  3. itmCtrol.ItemsSource 与 legend.xaml.cs。

我假设当您最终看到数据时,第一个引用已正确填充。第二个引用使用不需要的空 ObservableCollection 进行初始化(您可以节省初始化该对象的开销)。第三个设置为与第二个相同的空集合。

MainControl 方法中的代码将第二个引用设置为正确填充的集合,但不会以任何方式影响第三个引用 (itmCtrl.ItemsSource) - 它保留对空集合的引用。

我的猜测是,您在“正常工作”的按钮单击事件中的 legend.xaml.cs 中使用了如下代码。

itmCtrol.ItemsSource = allLines;

这会将 itmCtrol.ItemsSource 引用从空集合交换到正确填充的集合。

最简单的解决方案是将 allLines 字段替换为直接委托给 itmCtrol.ItemSource 属性的属性(使用 itmCtrol.ItemsSource 属性作为新属性的支持字段)。它看起来像这样。

 public ObservableCollection;全线
    {
        得到
        {
            return (IObservableCollection)itmCtrol.ItemsSource;
        }
        放
        {
            itmCtrol.ItemsSource = 值;
        }
    }

You actually have three references to the allLines collection to which you are trying to bind.

  1. allLines in the type that contains the MainControl method.
  2. allLines within legend.xaml.cs.
  3. itmCtrol.ItemsSource withing legend.xaml.cs.

I assume that the first reference is being populated correctly as you are eventually seeing the data. The second reference is initialized with an empty ObservableCollection that is not required (you could save yourself the overhead of initializing this object). The third is set to the same empty collection as the second.

Your code in the MainControl method sets the second reference to the correctly populated collection but does not affect the third refernce (itmCtrl.ItemsSource) in any way - it retains its reference to the empty collection.

My guess is that you are using code such as the following within legend.xaml.cs in the button click event that 'works just fine'.

itmCtrol.ItemsSource = allLines;

This would swap the itmCtrol.ItemsSource reference from the empty collection to the correctly populated one.

The simplest solution would be to replace the allLines field with a property that delegates straight to the itmCtrol.ItemSource property (use the itmCtrol.ItemsSource property as the backing field for the new property). It would look something like this.

    public ObservableCollection<StringLineInfo> AllLines
    {
        get
        {
            return (IObservableCollection<StringLineInfo>)itmCtrol.ItemsSource;
        }
        set
        {
            itmCtrol.ItemsSource = value;
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文