【问题标题】:Bind object to combobox and textbox将对象绑定到组合框和文本框
【发布时间】:2019-06-18 09:32:04
【问题描述】:

我有以下型号:

public class Tag : ObservableObject
{
    private int _id = -1;
    public int Id
    {
        get { return _id; }
        set
        {
            if (value != _id)
            {
                _id = value;
                OnPropertyChanged("Id");
            }
        }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (value != _name)
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    private string _freeText;
    public string FreeText
    {
        get { return _freeText; }
        set
        {
            if (value != _freeText)
            {
                _freeText = value;
                OnPropertyChanged("FreeText");
            }
        }
    }
}


public class Item : ObservableObject
{
    // ...

    private Tag _tag;
    public Tag Tag
    {
        get { return _tag; }
        set
        {
            if (value != _tag)
            {
                _tag= value;
                OnPropertyChanged("Tag");
            }
        }
    }
}

以下视图模型:

public class AppViewModel : ViewModelBase
{
    private Item _item;
    public Item Item
    {
        get { return _item; }
        set
        {
            if (_item != value)
            {
                _item = value;
                OnPropertyChanged("Item");
            }
        }
    }

    private List<Tag> _tags;
    public List<Tag> Tags
    {
        get { return _tags; }
        set
        {
            if (_tags != value)
            {
                _tags = value;
                OnPropertyChanged("Tags");
            }
        }
    }

    //...
 }

我的标签列表中填充了以下数据:

Tags = new List<Tag>() 
{
   new Tag()
   {
     Id = 0,
     Name = "Free Text"
   },
   new Tag()
   {
     Id = 1,
     Name = "Tag 1"
   },
   new Tag()
   {
     Id = 2,
     Name = "Tag 2"
   },
   new Tag()
   {
     Id = 3,
     Name = "Tag 3"
   }
 }

还有以下视图:

<ComboBox x:Name="cmbTags"
          ItemsSource="{Binding Tags}"
          DisplayMemberPath="Name"
          SelectedItem="{Binding Item.Tag}"/>

<TextBox x:Name="txtTagFreeText" Text="{Binding ElementName=cmbTags, Path=SelectedItem.FreeText}">
    <TextBox.Style>
        <Style TargetType="TextBox">
            <Setter Property="Visibility" Value="Collapsed" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding ElementName=cmbTags, Path=SelectedItem.Id}" Value="0">
                    <Setter Property="Visibility" Value="Visible"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBox.Style>
</TextBox>

我想要做的是将 ComboBox Items Source 绑定到我的标签列表,并将 SelectedItem 绑定到我的 Item。我设法设置了它。

然后,如果选择了 Id 为 0 的 Tag,我想显示 TextBox,这也是设置的。

我遇到的麻烦是将 TextBox 的文本与我的 Item.Tag 的 Property FreeText 绑定。​​

绑定有点工作,但它被应用于我的所有项目,所以每当我更改我的项目时,文本框都会显示我的最后一个输入。

我还尝试将 TextBox 文本绑定更改为:

{绑定 Item.Tag.FreeText}

但我也有同样的问题。

有人知道我做错了什么吗? 我需要发布更多代码吗?

感谢任何帮助或反馈。

谢谢。

【问题讨论】:

  • 在 TextBox 的文本绑定中,您使用 'cmbSubtitles' 作为 ElementName,您的意思是 cmbTags ComboBox 还是您没有发布其代码的其他控件?
  • @HenkaProgrammer 我的意思是 cmbTags,我更改了类以简化,将代码复制/粘贴到这里时我犯了一个错误。已修复,感谢您的关注。
  • 所选项目是否在此处反射Item.Tag
  • @AvinashReddy 如果您的意思是如果所选项目反映在我的视图模型中,那么是的,任何更改都将反映在我的视图模型中。
  • 然后尝试将其绑定到样式。

标签: wpf data-binding combobox textbox


【解决方案1】:

您正在绑定到一个空实例,AppViewModel 的 Item 属性应该使用实例进行初始化,但这不会解决您应该将 ComboBox 与 ViewModel 中的其他属性绑定的问题,让我们在 setter 中将其命名为 SelectedTag,处理你想要的逻辑。

public class AppViewModel : ObservableObject
{
    private Item _item = new Item();
    public Item Item
    {
        get { return _item; }
        set
        {
            if (_item != value)
            {
                _item = value;
                OnPropertyChanged("Item");
            }
        }
    }

    private Tag _SelectedTag;

    public Tag SelectedTag
    {
        get { return _SelectedTag; }
        set
        {
            if (_SelectedTag != value)
            {
                _SelectedTag = value;
                OnPropertyChanged("SelectedTag");
                Item.Tag = _SelectedTag;
                if (_SelectedTag.Id == 0)
                {
                    _SelectedTag.FreeText = "";
                }
            }
        }
    }


    private List<Tag> _tags;
    public List<Tag> Tags
    {
        get { return _tags; }
        set
        {
            if (_tags != value)
            {
                _tags = value;
                OnPropertyChanged("Tags");
            }
        }
    }

    // ...
}

和 XAML 代码:

<ComboBox x:Name="cmbTags"
      ItemsSource="{Binding Tags}"
      DisplayMemberPath="Name"
      SelectedItem="{Binding SelectedTag,Mode=TwoWay}"/> 
    <TextBox  Text="{Binding SelectedTag.FreeText,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
        <TextBox.Style>
            <Style TargetType="TextBox">
                <Setter Property="Visibility"  Value="Collapsed"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SelectedTag.Id}" Value="0">
                        <Setter Property="Visibility" Value="Visible"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
</TextBox>

更新

当标签更改 AppViewModel 上的 Raise Tag 属性时,您可以通过侦听 Item PropertyChanged 事件直接绑定的另一种方式,您是否有逻辑。

public class AppViewModel : ObservableObject
{
    private Item _item;
    public Item Item
    {
        get { return _item; }
        set
        {
            if (_item != value)
            {
                _item = value;
                _item.PropertyChanged -= _item_PropertyChanged;
                _item.PropertyChanged += _item_PropertyChanged;
                OnPropertyChanged("Item");
            }
        }
    }

    private List<Tag> _tags;
    public List<Tag> Tags
    {
        get { return _tags; }
        set
        {
            if (_tags != value)
            {
                _tags = value;
                OnPropertyChanged("Tags");
            }
        }
    }

    public AppViewModel()
    {
        Item = new Item();
        Tags = new List<Tag>()
        {
           new Tag()
           {
             Id = 0,
             Name = "Free Text"
           },
           new Tag()
           {
             Id = 1,
             Name = "Tag 1"
           },
           new Tag()
           {
             Id = 2,
             Name = "Tag 2"
           },
           new Tag()
           {
             Id = 3,
             Name = "Tag 3"
           }
         };
    }

    private void _item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(Item.Tag))
        {
            if (Item.Tag.Id == 0)
            {
                Item.Tag.FreeText = string.Empty;
            }
            OnPropertyChanged(nameof(Item));
        }
    }
}

并直接将ComboBox与Item Tag绑定

 <TextBox x:Name="txtTagFreeText" Text="{Binding Item.Tag.FreeText,Mode=TwoWay}">
        <TextBox.Style>
            <Style TargetType="TextBox">
                <Setter Property="Visibility" Value="Collapsed" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Item.Tag.Id}" Value="0">
                        <Setter Property="Visibility" Value="Visible"/> 
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
</TextBox>

【讨论】:

  • 好的,我明白你在说什么,这将解决我的问题。我试图避免在我的 ViewModel 和我的 Item 属性中复制 Tag 属性。为此,我试图直接绑定到我的项目中的标记属性。我想那是不可能的,对吧?
  • 可以通过其他方式,但如果您对我可以发布代码没有任何问题,则必须扩展项目类。
  • 感谢您的帮助,我可以根据您已经发布的内容找到可行的解决方案。您不需要发布代码,但是如果您能指出我应该做什么来直接绑定,那将有很大帮助。再次感谢您的帮助。
  • @lulasi 欢迎您,我发布的更新可能比第一个解决方案更适合您的需求。
猜你喜欢
  • 2016-05-02
  • 1970-01-01
  • 1970-01-01
  • 2017-05-25
  • 1970-01-01
  • 2021-01-01
  • 2013-10-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多