需要SIMPLE工作示例设置WPF MVVM ComboBox ItemsSource基于SelectedValue的第二个ComboBox [英] Need SIMPLE working example of setting WPF MVVM ComboBox ItemsSource based on SelectedValue of second ComboBox

查看:587
本文介绍了需要SIMPLE工作示例设置WPF MVVM ComboBox ItemsSource基于SelectedValue的第二个ComboBox的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

任何人都可以给我一个简单的工作示例,一个WPF MVVM应用程序根据ComboBox A的SelectedItem设置组合框B的ItemsSource?

Can anyone show me a simple working example for a WPF MVVM application to set the ItemsSource of combobox B based on the SelectedItem of ComboBox A?

我发现在这个网站,它得到所有太复杂的太快。

It seems from what I've found on this site that it gets all too complicated all too quickly.

什么是正确的MVVM的方式来完成它?

What's the "right" MVVM way to get it done?

谢谢。

编辑
我使用Didier的范例进行了更新。
我的XAML的提取:

EDIT I updated using Didier's example. An extract of my XAML:

<ComboBox Name="BrowserStackDesktopOS" ItemsSource="Binding Platforms.AvailableBrowserStackDesktopOSes}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopOSSelectedValue, Mode=TwoWay}"/>

<ComboBox Name="BrowserStackDesktopOSVersion" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopOSVersions}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopOSVersionSelectedValue, Mode=TwoWay}"/>

<ComboBox Name="BrowserStackDesktopBrowser" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopBrowsers}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopBrowserSelectedValue, Mode=TwoWay}"/>

<ComboBox Name="BrowserStackDesktopBrowserVersion" ItemsSource="{Binding Platforms.AvailableBrowserStackDesktopBrowserVersions}" SelectedIndex="0" SelectedItem="{Binding Platforms.BrowserStackDesktopBrowserVersionSelectedValue, Mode=TwoWay}"/>

我的代码示例:

public string BrowserStackDesktopOSSelectedValue {
        get { return (string)GetValue(BrowserStackDesktopOSSelectedValueProperty); }
        set { SetValue(BrowserStackDesktopOSSelectedValueProperty, value);
              AvailableBrowserStackDesktopOSVersions = AvailableBrowserStackDesktopPlatforms.GetOSVersions(BrowserStackDesktopOSSelectedValue);
              NotifyPropertyChanged("BrowserStackDesktopOSSelectedValue");
        }
    }

但是当我为第一个ComboBox选择一个值发生。我想通过填充下一个ComboBox的Itemsource。

However when I select a value for the first ComboBox nothing happens. I am wanting the Itemsource of the next ComboBox to by populated.

我做错了什么?

推荐答案

基本上,您需要在您的MVVM 2中显示组合框选项的值和选定值的两个属性。在开始只有第一集合如果silled与值。当第一选择值改变时,可以用适当的值填充第二集合。下面是一个实现示例:

Basically you need to expose in your MVVM 2 collection of values for combo box choices and two properties for selected values. In the begining only the first collection if silled with values. When the first selected value changes the second collection may be filled in with appropriate values. Here is an example of implementation:

代码背后:

public partial class MainWindow : Window
{

    public MainWindow()
    {
        InitializeComponent();

        //Set the data context of the window
        DataContext = new TestVM();
    }
}


public class TestVM : INotifyPropertyChanged
{

    #region Class attributes

    protected static string[] firstComboValues = new string[] { "Choice_1", "Choice_2" };

    protected static string[][] secondComboValues =
        new string[][] { 
                new string[] { "value_1_1", "value_1_2", "value_1_3" }, 
                new string[] { "value_2_1", "value_2_2", "value_2_3" } 
        };


    #endregion

    #region Public Properties

    #region FirstSelectedValue

    protected string m_FirstSelectedValue;

    /// <summary>
    ///  
    /// </summary>
    public string FirstSelectedValue
    {
        get { return m_FirstSelectedValue; }
        set
        {
            if (m_FirstSelectedValue != value)
            {
                m_FirstSelectedValue = value;
                UpdateSecondComboValues();
                NotifyPropertyChanged("FirstSelectedValue");
            }
        }
    }

    #endregion

    #region SecondSelectedValue

    protected string m_SecondSelectedValue;

    /// <summary>
    ///  
    /// </summary>
    public string SecondSelectedValue
    {
        get { return m_SecondSelectedValue; }
        set
        {
            if (m_SecondSelectedValue != value)
            {
                m_SecondSelectedValue = value;
                NotifyPropertyChanged("SecondSelectedValue");
            }
        }
    }

    #endregion

    #region FirstComboValues

    protected ObservableCollection<string> m_FirstComboValues;

    /// <summary>
    ///  
    /// </summary>
    public ObservableCollection<string> FirstComboValues
    {
        get { return m_FirstComboValues; }
        set
        {
            if (m_FirstComboValues != value)
            {
                m_FirstComboValues = value;
                NotifyPropertyChanged("FirstComboValues");
            }
        }
    }

    #endregion

    #region SecondComboValues

    protected ObservableCollection<string> m_SecondComboValues;

    /// <summary>
    ///  
    /// </summary>
    public ObservableCollection<string> SecondComboValues
    {
        get { return m_SecondComboValues; }
        set
        {
            if (m_SecondComboValues != value)
            {
                m_SecondComboValues = value;
                NotifyPropertyChanged("SecondComboValues");
            }
        }
    }

    #endregion

    #endregion

    public TestVM()
    {
        FirstComboValues = new ObservableCollection<string>(firstComboValues);
    }

    /// <summary>
    /// Update the collection of values for the second combo box
    /// </summary>
    protected void UpdateSecondComboValues()
    {
        int firstComboChoice;
        for (firstComboChoice = 0; firstComboChoice < firstComboValues.Length; firstComboChoice++)
        {
            if (firstComboValues[firstComboChoice] == FirstSelectedValue)
                break;
        }


        if (firstComboChoice == firstComboValues.Length)// just in case of a bug
            SecondComboValues = null;
        else
            SecondComboValues = new ObservableCollection<string>(secondComboValues[firstComboChoice]);

    }


    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

关联的XAML

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="window" x:Class="Testing1.MainWindow">

    <Grid>

        <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Width=" 300">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition Height="10"/>
                <RowDefinition/>
            </Grid.RowDefinitions>

            <ComboBox x:Name="FirstOne" ItemsSource="{Binding FirstComboValues}" SelectedItem="{Binding FirstSelectedValue, Mode=TwoWay}"/>

            <ComboBox x:Name="SecondOne" ItemsSource="{Binding SecondComboValues}" SelectedItem="{Binding SecondSelectedValue, Mode=TwoWay}" Grid.Row="2"/>

        </Grid>

    </Grid>

</Window>

正如你可以看到 SelectedValue 组合框以双向模式绑定,因此当组合框的 SelectedValue 属性更改时,它会更改VM端的值。在 FirstSelectedValue 属性设置 UpdateSecondComboValues()方法被调用来更新第二个组合框的值。

As you can see the SelectedValue properties of combo boxes are binded in TwoWay mode so when SelectedValue property of the combo box changes it changes the value on the VM side. And in FirstSelectedValue property setter UpdateSecondComboValues() method is called to update values for the second combo box.

编辑:

这是因为您混合了INotifPropertyChanged和DependencyObject。你应该选择其中之一。通常你在你的VM中实现INotifyPropertyChanged,并且属性设置器中的代码将工作。

It happens because you mixed both INotifPropertyChanged and DependencyObject. You should choose one of them. Usually you implement INotifyPropertyChanged in your VM and the code in the property setter will work.

如果你继承DependencyObject,你不应该在setter / getter 。它不会被双向绑定调用。它将在内部调用GetValue(...)。要能够对DependencyProperty更改执行操作,您应该使用属性更改的处理程序以不同的方式声明它:

If you inherit from DependencyObject however, you should not write any code in the setter/getter. It will never be called by the TwoWay binding. It will just call GetValue(...) internally. To be able to execute an action on DependencyProperty change you should declare it differently with a property changed handler:

#region BrowserStackDesktopOSSelectedValue 

/// <summary>
/// BrowserStackDesktopOSSelectedValue  Dependency Property
/// </summary>
public static readonly DependencyProperty BrowserStackDesktopOSSelectedValue Property =
    DependencyProperty.Register("BrowserStackDesktopOSSelectedValue ", typeof(string), typeof(YourVM),
        new FrameworkPropertyMetadata((string)null,
            new PropertyChangedCallback(OnBrowserStackDesktopOSSelectedValue Changed)));

/// <summary>
/// Gets or sets the BrowserStackDesktopOSSelectedValue  property. This dependency property 
/// indicates ....
/// </summary>
public string BrowserStackDesktopOSSelectedValue 
{
    get { return (string)GetValue(BrowserStackDesktopOSSelectedValue Property); }
    set { SetValue(BrowserStackDesktopOSSelectedValue Property, value); }
}

/// <summary>
/// Handles changes to the BrowserStackDesktopOSSelectedValue  property.
/// </summary>
private static void OnBrowserStackDesktopOSSelectedValue Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    YourVM target = (YourVM)d;
    string oldBrowserStackDesktopOSSelectedValue  = (string)e.OldValue;
    string newBrowserStackDesktopOSSelectedValue  = target.BrowserStackDesktopOSSelectedValue ;
    target.OnBrowserStackDesktopOSSelectedValue Changed(oldBrowserStackDesktopOSSelectedValue , newBrowserStackDesktopOSSelectedValue );
}

/// <summary>
/// Provides derived classes an opportunity to handle changes to the BrowserStackDesktopOSSelectedValue  property.
/// </summary>
protected virtual void OnBrowserStackDesktopOSSelectedValue Changed(string oldBrowserStackDesktopOSSelectedValue , string newBrowserStackDesktopOSSelectedValue )
{
    //Here write some code to update your second ComboBox content.
    AvailableBrowserStackDesktopOSVersions = AvailableBrowserStackDesktopPlatforms.GetOSVersions(BrowserStackDesktopOSSelectedValue);
}

#endregion

WPF snippets博士来编写DP,以便更快地完成。

By the way I always use Dr WPF snippets to write DPs so it goes much faster.

这篇关于需要SIMPLE工作示例设置WPF MVVM ComboBox ItemsSource基于SelectedValue的第二个ComboBox的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆