【问题标题】:How Do I Access Properties of an Object Selected from a ListBox WPF MVVM如何访问从 ListBox WPF MVVM 中选择的对象的属性
【发布时间】:2016-06-20 19:58:02
【问题描述】:

我的 ViewModel 中有一个绑定到可观察对象的列表框。当用户在列表框中选择一个项目时,SelectedItem 会触发“SelectedSandwich”属性。该值被保存到一个私有字段。属性 SandwichName 和 Description 是 Sandwich 对象的属性。我希望视图中的文本块显示选定的三明治名称和价格,但我不想将这些文本块绑定到列表框元素。 这是视图: '

<Window.DataContext>
    <vm:SandwichVM/>
</Window.DataContext>

<Window.Resources>

    <DataTemplate x:Key="lstSandwich">
        <Border BorderThickness="3" 
                CornerRadius="4" 
                HorizontalAlignment="Stretch"
                BorderBrush="Blue">
            <TextBlock HorizontalAlignment="Stretch">
                <Run Text="{Binding SandwichName}"/>
                <Run Text=" | " />
                <Run Text="{Binding Description}" />
                <Run Text=" | " />
                <Run Text="{Binding Price}" />
            </TextBlock>
        </Border>
    </DataTemplate>

    <DataTemplate x:Key="menu" >
        <Border>
            <TextBlock HorizontalAlignment="Stretch">
                <Run Text="{Binding SandwichName}"/>
                <Run Text="{Binding Price}" />
            </TextBlock>  
        </Border>
    </DataTemplate>

</Window.Resources>

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="2*"/>
    </Grid.RowDefinitions>

    <ListBox Grid.Row="0" x:Name="cboMenu" 
             ItemsSource="{Binding Sandwiches}"
             SelectedItem="{Binding SelectedSandwich, Mode=TwoWay}" 
             ItemTemplate="{StaticResource lstSandwich}"
             Margin="3">
    </ListBox>

    <Grid Grid.Row="1">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <TextBlock Grid.Row="0" 
                   HorizontalAlignment="Center" 
                   VerticalAlignment="Center" 
                   FontStretch="ExtraExpanded" 
                   FontFamily="Verdana"
                   FontSize="22"
                   >
            <Run Text="Your Selection"/>
        </TextBlock>
        <Grid Grid.Row="1">
            <ContentControl 
                ContentTemplate="{StaticResource menu}" 
                HorizontalAlignment="Stretch"
                Margin="5,0,5,0">
            </ContentControl>
           </Grid>
       </Grid>


   </Grid>
</Window>'

这是视图模型:

'class SandwichVM : INotifyPropertyChanged
{
    private Sandwich _selectedSandwich;
    private ObservableCollection<Sandwich> _sandwiches;



    public ObservableCollection<Sandwich> Sandwiches 
    {
        get { return _sandwiches; }
    }


    public SandwichVM()
    {
        //fake data for the list
        _sandwiches = new ObservableCollection<Sandwich>();
        _sandwiches.Add(new Sandwich("Pastrami", "Stacked high on rye bread     with a touch of mustard.", 8.50));
        _sandwiches.Add(new Sandwich("Tuna", "Fresh tuna salad on wheat with slice of cheddar cheese.", 6.50));
        _sandwiches.Add(new Sandwich("Steak", "Sliced grilled steak with sauteed mushrooms and onions.", 9.50));
        _sandwiches.Add(new Sandwich("Chicken Salad", "Juicy chunks of chicken breast, onions, fruit.", 6.50));
        _sandwiches.Add(new Sandwich("Buffalo Chicken", "Caliente! Fried chicken breast slathered with hot buffalo wing sauce.", 8.50));
        _sandwiches.Add(new Sandwich("Tofu", "I don't know how to make a tofu sandwich.", 1.50));

    }

    public Sandwich SelectedSandwich
    {
        get { return _selectedSandwich; }
        set
        {
            if (_selectedSandwich != value)
            {
                _selectedSandwich = value;
                RaisePropertyChangedEvent("SelectedSandwich");
            }
        } 
    }

    public string SandwichName
    {
        get { return _selectedSandwich.SandwichName; }
        set
        {
            _selectedSandwich.SandwichName = value;
            RaisePropertyChangedEvent("SandwichName");
        }

    }

    public string Description
    {
        get { return _selectedSandwich.Description; }
        set
        {
            _selectedSandwich.Description = value;
            RaisePropertyChangedEvent("Description");
        }
    }

    public string Price
    {
        get { return _selectedSandwich.Price.ToString(); }
        set
        {
            _selectedSandwich.Price = Convert.ToDouble(value);
            RaisePropertyChangedEvent("Price");
        }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChangedEvent(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }'

我尝试将 RaisePropertyChangedEvent 放入三个属性的设置器中(尽管我只需要阅读它们),但设置器从未执行。事实上,SelectedSandwich 属性的设置器永远不会被执行。每次都会执行get。我已经逐步完成了代码,但看不出问题出在哪里。 感谢您的帮助。

【问题讨论】:

    标签: c# wpf xaml mvvm listbox


    【解决方案1】:

    也许我不清楚,但您从 UI 设置的唯一属性是 SelectedSandwich 属性。如果在更改选定的列表框项目时设置正确,那么为什么不从其他地方绑定到 SelectedSandwich?

    因此,如果您希望视图中的某些文本块显示选定的三明治名称和价格,请尝试以下操作:

    <TextBlock Text="{Binding SelectedSandwich.Name}"/>
    <TextBlock Text="{Binding SelectedSandwich.Price}"/>
    

    或者如果你想使用你准备好的数据模板:

    <DataTemplate DataType="{x:Type sandwichVMNamespace:Sandwich}">
        <Border>
            <TextBlock HorizontalAlignment="Stretch">
                <Run Text="{Binding SandwichName}"/>
                <Run Text="{Binding Price}" />
            </TextBlock>  
        </Border>
    </DataTemplate>
    
    <Grid Grid.Row="1">
       <ContentControl 
          Content="{Binding SelectedSandwich}" 
          HorizontalAlignment="Stretch"
          Margin="5,0,5,0">
       </ContentControl>
    </Grid>
    

    你已经完成了......

    【讨论】:

    • 你的第一个例子是我的一个试验。我什么也得不到。我一直在寻找某种错字。我缺少一些非常简单的东西。你的第二个例子不会运行或不会编译,这取决于我做什么。命名空间是 ComboBox(我知道,但我从组合框开始)。我刚刚注意到视图模型的顶部不存在。我有 xmlns:vm="clr-namespace:ComboBox.ViewModel"。然后,如您所见,我在窗口上设置了数据上下文。所以我不明白你提出的“x:Type”。
    • DataTemplate 是您称为 x:Key="menu" 的那个,而网格是您在 xaml 页面底部的那个,只需粘贴它即可。没有理由不编译...不要打扰 x:Type 重要的想法是 "sandwichVMNamespace:Sandwich" 你必须像以前一样指定 Sandwich 类的命名空间,可能类似于 xmlns:sandwichVMNamespace=" clr 命名空间:ComboBox.ViewModel”。这一切都因为伟大的 wpf 而完成......
    猜你喜欢
    • 2011-03-24
    • 2016-04-10
    • 1970-01-01
    • 2017-06-09
    • 2019-03-02
    • 2020-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多