C# 将对象绑定到combobox会填充列表,但选择更改不会在CSharp中的对象中更新

C# 将对象绑定到combobox会填充列表,但选择更改不会在CSharp中的对象中更新,c#,binding,combobox,C#,Binding,Combobox,我有一个类ParamObj(它实现了INotifyPropertyChanged),其中包含类型为observeCollection的属性DefaultValues。MyParam类(也实现了INotifyPropertyChanged)包含两个属性:Name和IsSelected 单击按钮时,我正在用TextBlock和ComboBox控件填充StackPanel。集合DefaultValues中的每个Param都是ComboBox中的一个选项,其中Name属性表示该选项的文本,IsSelec

我有一个类
ParamObj
(它实现了
INotifyPropertyChanged
),其中包含类型为
observeCollection
的属性
DefaultValues
。My
Param
类(也实现了
INotifyPropertyChanged
)包含两个属性:
Name
IsSelected

单击按钮时,我正在用
TextBlock
ComboBox
控件填充
StackPanel
。集合
DefaultValues
中的每个
Param
都是
ComboBox
中的一个选项,其中
Name
属性表示该选项的文本,
IsSelected
是一个布尔值,表示该选项是否是当前在
组合框中选择的选项

    private void ParamComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!(sender is ComboBox)) return;

        ComboBox cb = sender as ComboBox;
        Param cp = (Param)cb.SelectedItem;
        if (cp.IsSelected == false)
        {
            foreach (Param p in cb.ItemsSource)
            {
                p.IsSelected = false;
            }
            cp.IsSelected = true;
        }
    }
Param
下面的类:

public class Param : INotifyPropertyChanged
{
    public enum ParamType
    {
        Unknown=-1,
        Text=0,
        Option=1,
        Multi=2
    }

    private string pName = string.Empty;
    private bool pSelected = false;
    private ParamType pType = ParamType.Unknown;

    public string Name { get { return pName; } set { pName = value; OnPropertyChanged("Name"); } }
    public bool IsSelected { get { return pSelected; } set { pSelected = value; OnPropertyChanged("IsSelected"); } }
    public ParamType Type { get { return pType; } }

    public Param(string name, bool selected)
    {
        this.pName = name;
        this.pSelected = selected;
        this.pType = ParamType.Option;
    }

    //INotifyPropertyChanged base
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}
public class ParamObj : INotifyPropertyChanged
{
    //ui type mapping
    public enum UITypeEnum
    {
        Textbox = 0,
        ComboBox = 1,
        CheckableComboBox = 2
    }

    private string name = string.Empty;
    private UITypeEnum uiType = UITypeEnum.Textbox;
    private ObservableCollection<Param> defaultVals = new ObservableCollection<Param>();
    private string propDescription = string.Empty;

    public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } }
    public UITypeEnum UIType { get { return uiType; } set { uiType = value; OnPropertyChanged("UIType"); } }
    public ObservableCollection<Param> DefaultValues { get { return defaultVals; } }
    public string Desc { get { return propDescription; } set { propDescription = value; } }

    //Initialization
    public ParamObj()
    {

    }

    public void ClearDefaultValues()
    {
        this.defaultVals.Clear();
        OnPropertyChanged("DefaultValues");
    }

    public void AddDefaultValue(Param objAdded)
    {
        this.defaultVals.Add(objAdded);
    }

    public void AddDefaultValueRange(Param[] objsToAdd)
    {
        foreach (Param o in objsToAdd)
        {
            this.defaultVals.Add(o);
        }
    }

    //INotifyPropertyChanged base
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}
ParamObj
以下类别:

public class Param : INotifyPropertyChanged
{
    public enum ParamType
    {
        Unknown=-1,
        Text=0,
        Option=1,
        Multi=2
    }

    private string pName = string.Empty;
    private bool pSelected = false;
    private ParamType pType = ParamType.Unknown;

    public string Name { get { return pName; } set { pName = value; OnPropertyChanged("Name"); } }
    public bool IsSelected { get { return pSelected; } set { pSelected = value; OnPropertyChanged("IsSelected"); } }
    public ParamType Type { get { return pType; } }

    public Param(string name, bool selected)
    {
        this.pName = name;
        this.pSelected = selected;
        this.pType = ParamType.Option;
    }

    //INotifyPropertyChanged base
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}
public class ParamObj : INotifyPropertyChanged
{
    //ui type mapping
    public enum UITypeEnum
    {
        Textbox = 0,
        ComboBox = 1,
        CheckableComboBox = 2
    }

    private string name = string.Empty;
    private UITypeEnum uiType = UITypeEnum.Textbox;
    private ObservableCollection<Param> defaultVals = new ObservableCollection<Param>();
    private string propDescription = string.Empty;

    public string Name { get { return name; } set { name = value; OnPropertyChanged("Name"); } }
    public UITypeEnum UIType { get { return uiType; } set { uiType = value; OnPropertyChanged("UIType"); } }
    public ObservableCollection<Param> DefaultValues { get { return defaultVals; } }
    public string Desc { get { return propDescription; } set { propDescription = value; } }

    //Initialization
    public ParamObj()
    {

    }

    public void ClearDefaultValues()
    {
        this.defaultVals.Clear();
        OnPropertyChanged("DefaultValues");
    }

    public void AddDefaultValue(Param objAdded)
    {
        this.defaultVals.Add(objAdded);
    }

    public void AddDefaultValueRange(Param[] objsToAdd)
    {
        foreach (Param o in objsToAdd)
        {
            this.defaultVals.Add(o);
        }
    }

    //INotifyPropertyChanged base
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(name));
    }
}
问题出在这里<代码>组合框
项已成功填充,并且选择了
IsSelected
值为
true
的选项(
Param
对象)。我认为会发生的是,当我在
组合框中更改所选选项时,
参数
对象的
IsSelected属性值(布尔值)将从
false
切换到
true
。这没有发生。因此,我将
cb.SelectionChanged+=ParamComboBox\u SelectionChanged
事件添加到
ComboBox

    private void ParamComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (!(sender is ComboBox)) return;

        ComboBox cb = sender as ComboBox;
        Param cp = (Param)cb.SelectedItem;
        if (cp.IsSelected == false)
        {
            foreach (Param p in cb.ItemsSource)
            {
                p.IsSelected = false;
            }
            cp.IsSelected = true;
        }
    }
通过调试,我确实看到
IsSelected
属性已正确更新,但我的
po
对象中的值未使用新值更新

如有任何建议,我们将不胜感激。我尽了最大的努力想弄明白,但我被卡住了


Brian

这似乎是一个非常简单的问题,但似乎没有简单或直接的方法将ComboBoxItem IsSelected绑定到给定属性。我想到的一个可能的解决方案是:

首先,向ComboBox中添加ComboBoxItem类型的样式,并向该样式添加触发器。当您选择ComboBoxItem并在步骤2中调用helper类时,将触发此触发器

     <ComboBox Name="TestCombo" ItemsSource="{Binding Path=DataSource.DefaultValues}" DisplayMemberPath="Name" SelectedValuePath="IsSelected" SelectionChanged="Test_SelectionChanged">
                <ComboBox.Resources>                    
                    <Style TargetType="{x:Type ComboBoxItem}">
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="StackOverflow:IsSelectedBehavior.IsSelected" Value="True"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="False">
                                <Setter Property="StackOverflow:IsSelectedBehavior.IsSelected" Value="False"></Setter>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </ComboBox.Resources>
            </ComboBox>
然后,创建一个IsSelectedBehaviorClass来处理您的IsSelected行为。此静态类将接收当前选定的ComboBoxItem,并相应地设置Param.IsSelected属性。大概是这样的:

    public static class IsSelectedBehavior
    {
        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached(
            "IsSelected", typeof (bool), typeof (IsSelectedBehavior), new UIPropertyMetadata(false, OnIsSelected));

        public static bool GetIsSelected(DependencyObject d)
        {
            return (bool) d.GetValue(IsSelectedProperty);
        }

        public static void SetIsSelected(DependencyObject d, bool value)
        {
            d.SetValue(IsSelectedProperty, value);
        }

        public static void OnIsSelected(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //Get current ComboBoxItem
            ComboBoxItem test = d as ComboBoxItem;
            //Get the current Param from the ComboBoxItem.Content
            Param p = test.Content as Param;
            //Set the Param.IsSelected property
            p.IsSelected = (bool) e.NewValue;
        }
    }
最后,您可以在SelectionChanged EventHandler上测试您的解决方案

    private void ParamComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Param selected = cb.SelectedItem as Param;
            if (selected != null)
            {
                Debug.WriteLine("Selection Changed: Selected " + selected.Name);
            }
            StringBuilder str = new StringBuilder();
            foreach (var obj in cb.Items)
            {
                Param p = obj as Param;
                str.Append("Name:" + p.Name + " IsSelected:" + p.IsSelected + Environment.NewLine);
                Debug.WriteLine(str);
            }
            MessageBox.Show(str.ToString());
        }

这是看起来非常简单的问题之一,但是似乎没有简单或直接的方法将ComboBoxItem IsSelected绑定到给定的属性。我想到的一个可能的解决方案是:

首先,向ComboBox中添加ComboBoxItem类型的样式,并向该样式添加触发器。当您选择ComboBoxItem并在步骤2中调用helper类时,将触发此触发器

     <ComboBox Name="TestCombo" ItemsSource="{Binding Path=DataSource.DefaultValues}" DisplayMemberPath="Name" SelectedValuePath="IsSelected" SelectionChanged="Test_SelectionChanged">
                <ComboBox.Resources>                    
                    <Style TargetType="{x:Type ComboBoxItem}">
                        <Style.Triggers>
                            <Trigger Property="IsSelected" Value="True">
                                <Setter Property="StackOverflow:IsSelectedBehavior.IsSelected" Value="True"></Setter>
                            </Trigger>
                            <Trigger Property="IsSelected" Value="False">
                                <Setter Property="StackOverflow:IsSelectedBehavior.IsSelected" Value="False"></Setter>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </ComboBox.Resources>
            </ComboBox>
然后,创建一个IsSelectedBehaviorClass来处理您的IsSelected行为。此静态类将接收当前选定的ComboBoxItem,并相应地设置Param.IsSelected属性。大概是这样的:

    public static class IsSelectedBehavior
    {
        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.RegisterAttached(
            "IsSelected", typeof (bool), typeof (IsSelectedBehavior), new UIPropertyMetadata(false, OnIsSelected));

        public static bool GetIsSelected(DependencyObject d)
        {
            return (bool) d.GetValue(IsSelectedProperty);
        }

        public static void SetIsSelected(DependencyObject d, bool value)
        {
            d.SetValue(IsSelectedProperty, value);
        }

        public static void OnIsSelected(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            //Get current ComboBoxItem
            ComboBoxItem test = d as ComboBoxItem;
            //Get the current Param from the ComboBoxItem.Content
            Param p = test.Content as Param;
            //Set the Param.IsSelected property
            p.IsSelected = (bool) e.NewValue;
        }
    }
最后,您可以在SelectionChanged EventHandler上测试您的解决方案

    private void ParamComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Param selected = cb.SelectedItem as Param;
            if (selected != null)
            {
                Debug.WriteLine("Selection Changed: Selected " + selected.Name);
            }
            StringBuilder str = new StringBuilder();
            foreach (var obj in cb.Items)
            {
                Param p = obj as Param;
                str.Append("Name:" + p.Name + " IsSelected:" + p.IsSelected + Environment.NewLine);
                Debug.WriteLine(str);
            }
            MessageBox.Show(str.ToString());
        }