【问题标题】:Binding usercontrol property to custom class将用户控件属性绑定到自定义类
【发布时间】:2018-03-11 05:11:54
【问题描述】:

在我的应用程序中,我在主窗口中使用了一个名为“ChannelControls”的usercontrol,我实例化了 6 次。

public partial class ChannelControls : UserControl
{
    CMiXData cmixdata = CMiXData.Instance;
    public ChannelControls()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public static readonly DependencyProperty ChannelSpriteCountProperty =
    DependencyProperty.Register("ChannelSpriteCount", typeof(string), typeof(ChannelControls), new PropertyMetadata("1"));
    [Bindable(true)]
    public string ChannelSpriteCount
    {
        get { return (string)this.GetValue(ChannelSpriteCountProperty); }
        set { this.SetValue(ChannelSpriteCountProperty, value); }
    }

我正在使用一个名为 cmixdata 的自定义类来保存我的应用程序的所有数据(它将包含 List 的字符串、双精度等的不同属性......)。 ChannelControls 将包含许多滑块、按钮和其他用户控件,但目前我正在尝试仅绑定其中一个。

这是这个自定义类的一部分,它将保存数据,它有一个私有构造函数,因为我需要从任何地方访问它:

[Serializable]
public class CMiXData : INotifyPropertyChanged
{
    private static CMiXData _instance = null;
    public static CMiXData Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new CMiXData();
            }
            return _instance;
        }
    }
    private CMiXData() { } //prevent instantiation from outside the class


    public event PropertyChangedEventHandler PropertyChanged;
    private void RaisePropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
        MessageBox.Show(propertyName);
    }


    private List<string> _SpriteCount = new List<string>(new string[] {"1", "1", "1", "1", "1", "1"});
    public List<string> SpriteCount
    {
        get { return _SpriteCount; }
        set
        {
            if(_SpriteCount != value)
            {
                _SpriteCount = value;
                RaisePropertyChanged("SpriteCount");
            }
        }
    }

下面是我尝试将 channelcontrol 属性 ChannelSpriteCount 绑定到我的单例类的方法:cmixdata。

<CMiX:ChannelControls x:Name="Layer0" Tag="0" Visibility="Visible" ChannelSpriteCount="{Binding SpriteCount[0], Mode=TwoWay}"/>

ChannelControls 被实例化的主用户控件上,datacontext 是这样设置的:

public partial class CMiX_UI : UserControl
{
    BeatSystem beatsystem = new BeatSystem();
    CMiXData cmixdata = CMiXData.Instance;

    public CMiX_UI()
    {
        InitializeComponent();
        this.DataContext = cmixdata;
    }

在 xaml 方面:

<UserControl
        x:Class="CMiX.CMiX_UI"
        DataContext="{x:Static CMiX:CMiXData.Instance}"

但由于某些原因,cmixdata 中的属性没有更新,始终具有默认值...

【问题讨论】:

  • CMiX:CounterChannelControls 应该是同一个 UserControl 类吗?
  • CMiX:Counter 在 ChannelControls 内
  • 除了UpdateSourceTrigger=PropertyChanged 毫无意义之外,Binding 应该可以工作,因为您已将 ChannelControls 的 DataContext 设置为 CMiXData 的实例,并且该 DataContext 值应由子元素继承。您可以尝试在调用 InitializeComponent 之前设置 DataContext。
  • 然而,一般来说,你不应该显式设置 UserControl 的 DataContext,原因是上面提到的,例如herehere.
  • Counter.Count是什么类型的?

标签: c# wpf


【解决方案1】:

UserControl 永远不应该有一个“自己的”视图模型实例。相反,它应该具有绑定到“外部”视图模型属性的依赖属性。

您的 ChannelsControl 会声明这样的属性(我认为 string 不是 count 的合适类型):

public partial class ChannelsControl : UserControl
{
    public static readonly DependencyProperty SpriteCountProperty =
        DependencyProperty.Register(
            nameof(SpriteCount), typeof(string), typeof(ChannelsControl));

    public string SpriteCount
    {
        get { return (string)GetValue(SpriteCountProperty); }
        set { SetValue(SpriteCountProperty, value); }
    }

    ...
}

在 ChannelsControl 的 XAML 中,您可以这样绑定它:

<CMiX:Counter Count="{Binding SpriteCount,
                      RelativeSource={RelativeSource AncestorType=UserControl}}"/>

您现在可以使用如下所示的 UserControl,您可以将 Count 属性绑定到 DataContext 中的视图模型,如下所示:

<Window.DataContext>
    <local:CMiXData />
</Window.DataContext>
...

<local:ChannelsControl SpriteCount="{Binding SpriteCount[0]}" ... />

您现在也可以像这样在 ItemsControl 的 ItemTemplate 中使用 ChannelsControl:

<ItemsControl ItemsSource="{Binding SpriteCount}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <local:ChannelsControl SpriteCount="{Binding}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

编辑:将 Window 的 DataContext 设置为您的视图模型单例实例,如下所示:

<Window ... DataContext="{x:Static local:CMiXData.Instance}" >

或者在后面的代码中,在 MainWindow 构造函数中:

DataContext = CMiXData.Instance;

【讨论】:

  • 是的,我试过了,但是 ChannelControls 会被复制 6 次,而且它们不会绑定到第一个元素。 ChannelControls 1 将绑定到第一个,ChannelControls 2 将绑定到第二个等等...
  • 我明白你的回答,谢谢,但假设我想动态创建更多 ChannelControls 实例,我别无选择,只能在后面的代码中编写所有绑定对吗?
  • 抱歉,今天刚检查过,但仍然无法正常工作,我无法在 XAML 中声明数据上下文,因为构造函数是私有的。我需要这个类在任何地方都可以访问,所以它有一个私有构造函数。
  • 感谢您对此的支持,但我必须在某处遗漏一个细节,我已经更新了我的帖子。
猜你喜欢
  • 1970-01-01
  • 2011-05-11
  • 1970-01-01
  • 2011-08-29
  • 2011-06-22
  • 2013-12-25
  • 1970-01-01
  • 2012-08-29
相关资源
最近更新 更多