WPF - 无法清除数据绑定项目控件中的项目

时间:2009-07-14 08:56:18

标签: wpf databound-controls

我创建了一个组合框并将其绑定到一个observableCollection。

像myCmbBox.ItemsSource = myObsCollObj

之类的东西

我的场景是onLoad应用程序我将使用一些值填充我的observableCollection。现在,我的UI也会自动刷新这些值。如果用户从另一个组合框中选择一个不同的值(比如说combobox2),我现在需要清除myCmbBox中的所有现有项目。我尝试使用以下选项

   myObsCollObj.Remove()
   myObsCollObj.RemoveAt()
   myObsCollObj.Clear()
   (myCmbBox.ItemsSource as ObservableCollection<string>).Remove()

   myCmbBox = null;
   myCmbBox.Items.Clear()

上述选项均无效,我得到一个例外,说“价值不能为空”。

现在我的问题是,如何清除我的收藏并添加新值(这也应该刷新我的用户界面)

谢谢, 兰芝斯

使用代码更新

XAML

    <Page x:Class="ThrowAwayProto.Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Page1">
    <StackPanel>
        <Label HorizontalAlignment="Center">Environment Modules</Label>
        <ComboBox Name="lstEnv" SelectionChanged="lstEnv_SelectionChanged"></ComboBox>

        <Label HorizontalAlignment="Center">Module Ids</Label>
        <ComboBox Name="cmbModId" SelectionChanged="cmbModId_SelectionChanged"></ComboBox>

        <Label HorizontalAlignment="Center">Environment Modules</Label>
        <ListBox Name="lstSites"></ListBox>

        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="600"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid Grid.Column="0">
                <Grid.RowDefinitions>
                    <!-- Recipe Type -->
                    <RowDefinition Height="30"/>
                    <!-- Recipe Mode -->
                    <RowDefinition Height="30"/>
                    <!-- Include expired recipe -->
                    <RowDefinition Height="30"/>
                    <!-- Search for promoted recipe -->
                    <RowDefinition Height="30"/>
                    <!-- Site -->
                    <!--<RowDefinition Height="30"/>-->
                    <!-- Activity -->
                    <!--<RowDefinition Height="30"/>-->
                </Grid.RowDefinitions>

                <StackPanel Orientation="Horizontal" Grid.Row="0" Width="100">
                    <Label>Recipe Type</Label>
                    <ComboBox Name="cmbRecipeType" SelectionChanged="cmbRecipeType_SelectionChanged"/>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Grid.Row="1">
                    <Label>Recipe Mode</Label>
                    <ComboBox Name="cmbRecipeMode">
                        <ComboBoxItem>PRODUCTION</ComboBoxItem>
                        <ComboBoxItem>ENGINEERING</ComboBoxItem>
                    </ComboBox>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Grid.Row="2">
                    <Label>Include Expired Recipe?</Label>
                    <RadioButton>Yes</RadioButton>
                    <RadioButton>No</RadioButton>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Grid.Row="3">
                    <Label>Search for promoted Recipe?</Label>
                    <CheckBox Name="chkPromRecipe"/>
                </StackPanel>

                <!--<StackPanel Orientation="Horizontal" Grid.Row="4">
                    <Label>Site</Label>
                    <ComboBox Name="cmbSite"/>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Grid.Row="5">
                    <Label>Activity</Label>
                    <ComboBox Name="cmbActivity"/>
                </StackPanel>-->                

            </Grid>

            <Grid Name="grdCol2" Grid.Column="1">

            </Grid>
        </Grid>

        <Button Name="btnSearch" Click="btnSearch_Click">Search</Button>

    </StackPanel>
</Page>

背后的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml.Linq;
using Intel.ATTD.Data;
using Intel.Auto.MW.Frameworks;
using System.Collections.ObjectModel;

namespace ThrowAwayProto
{
    /// <summary>
    /// Interaction logic for Page1.xaml
    /// </summary>
    public partial class Page1 : Page
    {
        private string _types;

        private Dictionary<string,string> _envList;
        private Dictionary<string, string> _modNameToId;
        private Dictionary<string, string> _selCritNameToId;
        private List<string> _selCritNames;
        private Dictionary<string, ObservableCollection<string>> _selCritNameToList;

        public ObservableCollection<string> _modIdList { get; set; }
        public ObservableCollection<string> _siteList { get; set; }
        public ObservableCollection<string> _recipeTypes { get; set; }

        public Page1()
        {
            InitializeComponent();
            _envList = new Dictionary<string, string>();
            _modIdList = new ObservableCollection<string>();
            _siteList = new ObservableCollection<string>();
            _modNameToId = new Dictionary<string, string>();
            _recipeTypes = new ObservableCollection<string>();
            _selCritNames = new List<string>();
            _selCritNameToId = new Dictionary<string, string>();
            _selCritNameToList = new Dictionary<string, ObservableCollection<string>>();

            cmbModId.ItemsSource = _modIdList;
            lstSites.ItemsSource = _siteList;

            LoadEnvModule();
            GetSites();
        }

        /// <summary>
        /// First step in ASNC
        /// </summary>
        private void LoadEnvModule()
        {

            string environments = ConsoleApplication1.Program.CallEnvironMentModuleMgntService_GetAllEnvironments();

            // Load Xml
            XElement document = XElement.Parse(environments);

            IEnumerable<XElement> childElements =
                from envModule in document.Elements("Environment")
                select envModule;

            foreach (XElement el in childElements)
                _envList.Add(el.Element("Name").Value, el.Element("Id").Value);

            List<string> envNames = new List<string>();
            foreach (string names in _envList.Keys)
                envNames.Add(names);

            // Set the ListBox value
            lstEnv.ItemsSource = envNames;
        }

        /// <summary>
        /// Step 2
        /// </summary>
        private void GetModuleByEnvId()
        {
            string selectedEnvId = lstEnv.SelectedItem as string;
            selectedEnvId = _envList[selectedEnvId];

            DataCollection reqDC = new DataCollection("GetModuleByEnvID");
            reqDC.add(new Parameter("Idsid", "rchevan"));            
            reqDC.add(new Parameter("Id", selectedEnvId));

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "EnvModuleMgntService", "GetModuleByEnvID");

            string modules = reply[0].toXML();
            // Extract required info
            // Load Xml
            XElement document = XElement.Parse(modules);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("Module")
                select mod;

            if (_modIdList.Count > 0)
            {
                _modNameToId.Clear();
                _modIdList.Clear();
            }

            foreach (XElement el in childElements)
            {                
                _modNameToId.Add(el.Element("Name").Value, el.Element("Env_Mod_Id").Value);
                _modIdList.Add(el.Element("Name").Value);
            }

            // Rebind when a new environment is selected

        }

        private static DataCollection[] InvokeATMIA(Request[] requests, string serName, string opName)
        {
            DataCollection[] reply = null;
            ATMIAProxy proxy = new ATMIAProxy();

            ATMIAMessage input = new ATMIAMessage();
            input.AddParameter("ServiceName", serName);
            input.AddParameter("OperationName", opName);
            input.AddObject(requests);

            ATMIAMessage output = proxy.InvokeMethod(input);

            if (output.GetTxnSuccess())
            {
                return output.GetBody<DataCollection[]>();
            }

            return null;
        }

        private void lstEnv_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {            
            GetModuleByEnvId();
        }

        /// <summary>
        /// Call GetModuleAliasData
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbModId_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            // Get Module Alias data
            // This is the actual search recipe
            string selectedModId = cmbModId.SelectedItem as string;

            //string selectedModId = "DEFLUX";
            selectedModId = _modNameToId[selectedModId];

            DataCollection reqDC = new DataCollection("GetModuleAliasData");
            reqDC.add(new Parameter("Env_Mod_Id", selectedModId));
            reqDC.add(new Parameter("Idsid", "rchevan"));

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "EnvModuleMgntService", "GetModuleAliasData");

            // Load the Recipe Types and SelCritNames here
            _types = reply[0].toXML();
            // Extract required info
            // Load Xml
            XElement document = XElement.Parse(_types);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("RecipeType")
                select mod;

            foreach (XElement el in childElements)
                _recipeTypes.Add(el.Element("RecipeTypeName").Value);

            cmbRecipeType.ItemsSource = _recipeTypes;


        }

        private void GetSites()
        {
            DataCollection reqDC = new DataCollection("GetEnvToSite");
            reqDC.add(new Parameter("Idsid", "rchevan"));

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "EnvModuleMgntService", "GetEnvToSite");

            string sites = reply[0].toXML();
            // Extract required info
            // Load Xml
            XElement document = XElement.Parse(sites);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("Environment").Elements("Site")
                select mod;

            foreach (XElement el in childElements)
                _siteList.Add(el.Element("SiteName").Value);

        }

        private void GetSearchAttributes()
        {
            string selectedModId = cmbModId.SelectedItem as string;
            //string selectedModId = "DEFLUX";
            selectedModId = _modNameToId[selectedModId];

            DataCollection reqDC = new DataCollection("GetSearchAttributes");
            reqDC.add(new Parameter("Env_Mod_Id", selectedModId));
            reqDC.add(new Parameter("EntityRequired", "N"));
            reqDC.add(new Parameter("Idsid", "rchevan"));

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "RecipeSearchService", "GetSearchAttributes");

            string selCrits = reply[0].toXML();
            // Extract required info
            // Load Xml
            XElement document = XElement.Parse(selCrits);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("Sel_Crit_Ids")
                select mod;

            if (_selCritNameToId.Count > 0)
                _selCritNameToId.Clear();

            foreach (XElement el in childElements)
                _selCritNameToId.Add(el.Element("Sel_Crit_Name").Value, el.Element("Sel_Crit_Id").Value);

            GetOptSearchAttributes();

        }

        private void GetOptSearchAttributes()
        {
            DataCollection reqDC = new DataCollection("GetSearchAttributes");
            reqDC.add(new Parameter("Idsid", "rchevan"));

            DataCollection selCritDC = new DataCollection("Sel_Crit_Ids");
            foreach (string selCritName in _selCritNames)
            {
                string selCritId = _selCritNameToId[selCritName];

                selCritDC.add(new Parameter("Sel_Crit_Id", selCritId));
                reqDC.add(selCritDC);
            }

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "RecipeSearchService", "GetOptSearchAttributeValues");

            string instSelCrits = reply[0].toXML();
            // Extract required info
            // Load Xml
            XElement document = XElement.Parse(instSelCrits);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("InstanceForSelCrit")
                select mod;

            //if (_selCritNameToId.Count > 0)
            //    _selCritNameToId.Clear();

            foreach (string selCrit in _selCritNames)
            {
                string selCritId = _selCritNameToId[selCrit];

                ObservableCollection<string> selCritNameList = new ObservableCollection<string>();
                _selCritNameToList.Add(selCrit, selCritNameList);

                foreach (XElement el in childElements)
                {
                    string selCritRecv = el.Element("Sel_Crit_Id").Value;

                    if (string.Equals(selCritId, selCritRecv))
                    {
                        string selCritName = el.Element("Sel_Crit_Inst_Name").Value;
                        selCritNameList.Add(selCritName);
                    }
                }
            }

            GridLengthConverter myGridLengthConverter = new GridLengthConverter();
            GridLength gl1 = (GridLength)myGridLengthConverter.ConvertFromString("50");

            // Populate values to the right hand side of the 
            // search screen
            int counter = 0;
            foreach (string selCrit in _selCritNames)
            {
                ComboBox cmbBox = new ComboBox();
                cmbBox.ItemsSource = _selCritNameToList[selCrit];
                Grid.SetRow(cmbBox, counter);
                Grid.SetColumn(cmbBox, 1);

                grdCol2.Children.Add(cmbBox);

                ++counter;
            }

        }

        /// <summary>
        /// Based on the Recipe Type selected load other information
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cmbRecipeType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string selectedRecipeType = cmbRecipeType.SelectedItem as string;

            // Retrieve all Sel_Crit_Names to display
            XElement document = XElement.Parse(_types);

            IEnumerable<XElement> childElements =
                from mod in document.Elements("RecipeType")
                select mod;

            GridLengthConverter myGridLengthConverter = new GridLengthConverter();
            GridLength gl1 = (GridLength)myGridLengthConverter.ConvertFromString("50");

            // Clear before adding new columns
            grdCol2.ColumnDefinitions.Clear();
            grdCol2.RowDefinitions.Clear();

            ColumnDefinition colDef1 = new ColumnDefinition();
            ColumnDefinition colDef2 = new ColumnDefinition();
            grdCol2.ColumnDefinitions.Add(colDef1);
            grdCol2.ColumnDefinitions.Add(colDef2);

            int counter = 0;

            if (_selCritNames.Count > 0)
                _selCritNames.Clear();

            foreach (XElement el in childElements)
            {
                string recipeType = el.Element("RecipeTypeName").Value;

                if (string.Equals(selectedRecipeType, recipeType))
                {
                    IEnumerable<XElement> aliases =
                    from mod in el.Elements("Aliases")
                    select mod;

                    foreach (XElement al in aliases)
                    {
                        string element = al.Element("Sel_Crit_Name").Value;

                        _selCritNames.Add(element);

                        Label label = new Label();
                        label.Content = element;

                        RowDefinition row = new RowDefinition();
                        grdCol2.RowDefinitions.Add(row);
                        grdCol2.RowDefinitions[counter].Height = gl1;
                        Grid.SetRow(label, counter);
                        Grid.SetColumn(label, 0);

                        grdCol2.Children.Add(label);

                        ++counter;
                    }
                    break;
                }

            }



            // Now fill the values for the fields retrieved above 
            // in the loop
            GetSearchAttributes();
        }

        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            DataCollection reqDC = new DataCollection("SearchLinkRecipe");
            reqDC.add(new Parameter("Env_Mod_Id", cmbModId.SelectedItem as string));
            reqDC.add(new Parameter("RecipeType", cmbRecipeType.SelectedItem as string));
            reqDC.add(new Parameter("RecipeMode", "PRODUCTION"));
            reqDC.add(new Parameter("ExpiredRecipe", "N"));
            reqDC.add(new Parameter("Site", "CHANDLER, ARIZONA"));
            reqDC.add(new Parameter("PromotedStatus", "N"));
            reqDC.add(new Parameter("SearchType", "Dummy"));
            reqDC.add(new Parameter("LastUpdatedBy", "rchevan"));

            DataCollection keyDC1 = new DataCollection("Key");
            keyDC1.add(new Parameter("KeyCriteria", _selCritNames[0]));
            keyDC1.add(new Parameter("KeyValue", "*"));
            reqDC.add(keyDC1);

            DataCollection keyDC2 = new DataCollection("Key");
            keyDC2.add(new Parameter("KeyCriteria", _selCritNames[1]));
            keyDC2.add(new Parameter("KeyValue", "*"));
            reqDC.add(keyDC2);

            //DataCollection keyDC3 = new DataCollection("Key");
            //keyDC3.add(new Parameter("KeyCriteria", "OPERATIONGROUP"));
            //keyDC3.add(new Parameter("KeyValue", "*"));
            //reqDC.add(keyDC3);

            Request reqObj = new Request("Dummy", "Dummy");
            reqObj.add(reqDC);

            Request[] requests = new Request[1];
            requests[0] = reqObj;

            DataCollection[] reply = InvokeATMIA(requests, "RecipeSearchService", "SearchLinkRecipe");
        }

    }
}

2 个答案:

答案 0 :(得分:2)

听起来您的ComboBox将其SelectedItem或SelectedValue属性绑定到不允许为null的内容。因此,当您尝试清除ComboBox的Items属性所绑定的集合时,它会尝试为该属性分配“null”并引发异常。

可能有一种非常好的WPF-y方式来解决它。我可能首先尝试通过将其更新模式设置为Explicit来暂时挂起绑定,然后清除集合:

var binding = BindingOperations.GetBinding(myCmdBox, ComboBox.SelectedItemProperty);
binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
myObservableCollection.Clear();
// repopulate the collection here
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

这只是一个建议。我可能正在咆哮错误的树,但它可能会给你一些线索,说明你为什么会收到错误。

<强>更新

哇 - 这是很多代码。遗憾的是你无法将其降低到重现问题所需的最低限度。

我假设您的异常是从cmbRecipeType_SelectionChanged事件处理程序中抛出的。如果是这种情况,您有两种选择:

  1. 在该方法中放置一个断点,找出抛出异常的内容。它可能很简单,就像第一行产生一个空值:

    string selectedRecipeType = cmbRecipeType.SelectedItem as string;

  2. 如果这是真的,你可能会在此之后直接打击它:

    if (selectedRecipeType == null) return;
    

    这将阻止任何后续代码访问selectedRecipeType,就像它是非空的一样。

    1. 执行类似于我最初建议的操作,并在清除项目之前暂时从ComboBox中取消该事件处理程序。然后再将它连接起来。

答案 1 :(得分:2)

有些人使用假人的方法“下车”并再次进入车内:

myCmbBox.ItemsSource = null;
myCmbBox.ItemsSource = yourLoadMethod();