【问题标题】:WPF twoway Databinding listbox to model in WPF can't get selected value在 WPF 中建模的 WPF 双向数据绑定列表框无法获取选定值
【发布时间】:2016-01-18 21:06:54
【问题描述】:

我在 WPF 中的数据绑定中苦苦挣扎,四处搜索后我仍然看不到我缺少什么来让模型使用列表中的选定项目进行更新。 我有 2 个实体,一个 Slot 和一个 SlotType

public class Slot : BindableObject, INotifyPropertyChanged
{
    private int slotID;
    public int SlotID
    {
        get { return slotID; }
        set
        {
            if (slotID != value)
            {
                slotID = value;
                RaisePropertyChanged("SlotID");
            }
        }
    }
    private string user;
    public string SlotUser
    {
        get { return user; }
        set
        {
            if (user != value)
            {
                user = value;
                RaisePropertyChanged("SlotUser");
            }
        }
    }

    private int slotUserID;
    public int SlotUserID
    {
        get { return slotUserID; }
        set
        {
            if (slotUserID != value)
            {
                slotUserID = value;
                RaisePropertyChanged("SlotUserID");
            }
        }
    }

    private int slotType;
    public int SlotType
    {
        get { return slotType; }
        set
        {
            if (slotType != value)
            {
                slotType = value;
                RaisePropertyChanged("SlotType");
            }
        }
    }

    private DateTime slotStartDateTime;
    public DateTime SlotStartDateTime
    {
        get { return slotStartDateTime; }
        set
        {
            if (slotStartDateTime != value)
            {
                slotStartDateTime = value;
                RaisePropertyChanged("SlotStartDateTime");
            }
        }
    }
public class SlotType : BindableObject, INotifyPropertyChanged
{
    private int slotTypeID;
    public int SlotTypeID
    {
        get { return slotTypeID; }
        set
        {
            if (slotTypeID != value)
            {
                slotTypeID = value;
                RaisePropertyChanged("SlotTypeID");
            }
        }
    }
    private string slotTypeDesc;
    public string SlotTypeDesc
    {
        get { return slotTypeDesc; }
        set
        {
            if (slotTypeDesc != value)
            {
                slotTypeDesc = value;
                RaisePropertyChanged("SlotTypeDesc");
            }
        }
    }
    public override string ToString()
    {
        return SlotTypeDesc;
    }
}

然后我创建一个包含两者的类并将我的窗口上下文设置为此类。

public class SlotWithTypes 
{
    public ObservableCollection<SlotType> slotTypes { get; set; }
    public Slot slot { get; set; }
}

在我的主窗口中进行测试,如果需要,打开新窗口,显示 SlotTypes 列表,供用户选择与正在创建的插槽相关的类型。

Slot slot = new Slot();
slot.SlotStartDateTime = item.SlotStartDateTime;
if (item.SlotType == 0)
{
    SlotWithTypes swtype = new SlotWithTypes();
    swtype.slotTypes = slotTypes;
    swtype.slot = slot;

    SelectSlotType stype = new SelectSlotType();
    stype.DataContext = swtype;
    stype.ShowDialog();
}

终于在我的 XAML 中我有了我的列表框

<Grid>
    <ListBox Name="lstSlotTypes" 
             HorizontalAlignment="Left" 
             Height="200" 
             Margin="0,10,0,0" 
             VerticalAlignment="Top" 
             Width="194"                 
             ItemsSource="{Binding slotTypes}" 
             SelectedItem="{Binding Path=slot.Type, Mode=TwoWay}"
             SelectedValue="{Binding slotTypes.SlotTypeID, Mode=TwoWay}" 
             SelectedValuePath="{Binding slot.Type, Mode=TwoWay}" 
             DisplayMemberPath="{Binding slotTypes.SlotTypeDesc}"                  
             SelectionChanged="lstSlotTypes_SelectionChanged">
    </ListBox>
    <TextBox HorizontalAlignment="Left" 
             Height="23" 
             Margin="10,246,0,0" 
             TextWrapping="Wrap" 
             Text="{Binding slot.SlotStartDateTime, Mode=TwoWay}" 
             VerticalAlignment="Top" 
             Width="74"/>
</Grid>

为了测试,我放入了一个绑定到 slotstartdatetime 的文本框,它可以工作并更新回我的模型。我在列表框上尝试了多种绑定格式,可以让我的 SlotTypes 列表显示 put can't get the Slot entity to update with selected value.

我意识到这已成为一个很长的问题,但如果有人能看出我做错了什么,请教一下?

【问题讨论】:

  • 这是什么逻辑? 1. 打开窗口有物品清单吗? 2. 列表框中是否有任何项目?
  • 您确定,在 SelectedValuePath 和 DisplayMemberPath 中您需要绑定吗? :) 必须有一些属性名称。

标签: c# wpf xaml data-binding listbox


【解决方案1】:

我可以在这里看到很多问题,首先,您的 xaml 应该是这样才能完成这项工作的:

    <ListBox Name="lstSlotTypes" HorizontalAlignment="Left" Height="200" Margin="0,10,0,0" VerticalAlignment="Top" Width="194"                 
        ItemsSource="{Binding slotTypes}" 
             SelectedValue="{Binding Path=slot.SlotType}"
             SelectedValuePath="SlotTypeID"
  DisplayMemberPath="SlotTypeDesc" >
    </ListBox>

现在,当您不知道哪些绑定不起作用时,在大多数情况下,这是由于输出窗口中可见的绑定错误,这真的很有帮助,所以每次都看看那里。例如,在您的 xaml 中,输出窗口显示的是:

System.Windows.Data 错误:40:BindingExpression 路径错误:“类型” 在“对象”“插槽”(HashCode=62085918)上找不到属性。 BindingExpression:Path=slot.Type; DataItem='SlotWithTypes' (哈希码=23184054);目标元素是“列表框” (名称='lstSlotTypes');目标属性是“SelectedItem”(类型 “对象”)System.Windows.Data 错误:40:BindingExpression 路径 错误:在“对象”上找不到“SlotTypeID”属性 ''ObservableCollection`1' (HashCode=58050239)'。 BindingExpression:Path=slotTypes.SlotTypeID; DataItem='SlotWithTypes' (哈希码=23184054);目标元素是“列表框” (名称='lstSlotTypes');目标属性是“SelectedValue”(类型 '对象')

如您所见,已经有一些信息。

现在你的 xaml 出了什么问题:

  • Slot 类没有Type 属性,只有SlotType 属性
  • 您不能绑定到slot.SlotType SelectedItem,因为SelectedItem 包含来自ItemsSource 的整个选定对象 - 在这种情况下是SlotType 类,而绑定属性slot.SlotTypeint 类型。所以你需要使用SelectedValue 属性,而不是SelectedItem 在这种情况下
  • 看起来您将SelectedValueSelectedValuePath 混淆了,SelectedValue 绑定指向 datacontext 中应存储所选项目值的对象,在这种情况下 = slot.SlotType
  • SelectedValuePath - 它是所选项目上的路径,应该设置为所选值 - 它是一个静态字符串,无需绑定任何东西
  • DisplayMemberPath - 如上所述,它是一个静态字符串,指示保存需要显示的值的属性的路径 - 无需在此处绑定任何内容

【讨论】:

  • 非常感谢 Alek,这是一个很棒的答案,还有这么多信息。
  • @user5466211 只是为了好玩,看看这个article。我希望它会对你有所帮助。
  • @Noctis 感谢非常有帮助,我一直在寻找年龄,找不到像 Alek 的回答和您的文章一样有用的东西。
【解决方案2】:

代码有几个问题:

  1. Visual Studio OUTPUT 窗口中有两个绑定错误(如果列表框源已定义并包含元素),原因是 SelectedValuePath 绑定错误和源类型冲突。这是对我有用的解决方案。
  2. 数据上下文收集初始化:

    private void InitDataContext()
    {
        DataContext = new SlotWithTypes
        {
            slot = new Slot(),
            slotTypes = new ObservableCollection<SlotType>(new List<SlotType>
            {
                new SlotType
                {
                    SlotTypeDesc = "Bla Bla 1",
                    SlotTypeID = 1,
                },
                new SlotType
                {
                    SlotTypeDesc = "Bla Bla 2",
                    SlotTypeID = 2,
                }
            })
        };
    }
    
  3. Xaml 代码:

    <Grid>
    <ListBox Name="lstSlotTypes" HorizontalAlignment="Left" 
             Height="200" Margin="0,10,0,0" 
             VerticalAlignment="Top" Width="194" 
             ItemsSource="{Binding slotTypes}" 
             SelectedValue="{Binding SelectedSlotType, Mode=TwoWay}" 
             SelectedValuePath="SlotTypeID" DisplayMemberPath="SlotTypeDesc" 
             SelectionChanged="lstSlotTypes_SelectionChanged">
    </ListBox></Grid>
    
  4. SlotWithTypes 代码:

    public ObservableCollection<SlotType> slotTypes { get; set; }
    
    public Slot slot
    {
        get { return _slot; }
        set
        {
            _slot = value;
            OnPropertyChanged();
        }
    }
    
    public int SelectedSlotType
    {
        get { return _selectedSlotType; }
        set
        {
            _selectedSlotType = value;
            OnPropertyChanged();
            UpdateSlot(SelectedSlotType);
        }
    }
    
    private void UpdateSlot(int selectedSlotType)
    {
        slot.SlotType = selectedSlotType;
    }
    
  5. 因此,每次我进行选择时,插槽的 SlotType 属性都会更改为使用新值定义的广告。在这里做你的逻辑。

问候,

【讨论】:

  • @Golik 感谢您的努力,你是对的,我的 xaml 都错了
猜你喜欢
  • 1970-01-01
  • 2010-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-01
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多