1

我创建了一个组合框并将其绑定到一个 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()

上述选项都不起作用,我收到一个异常说“值不能为空”。

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

谢谢, 兰吉斯

使用代码更新

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");
        }

    }
}
4

2 回答 2

2

It sounds like your ComboBox has its SelectedItem or SelectedValue property bound to something that isn't allowed to be null. So when you try to clear the collection that the ComboBox's Items property is bound to, it's trying to assign "null" to that property and an exception is being raised.

There's probably a really nice WPF-y way to get around it. I'd probably start by trying to temporarily suspend the binding by setting its update mode to Explicit and then clear the collection:

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

That's just a suggestion. I might be barking up the wrong tree but it might give you some clues as to why you're getting the error.

Update

Wow - that's a lot of code. Shame you couldn't reduce it down to the bare minimum necessary to reproduce the problem.

I'm assuming your exception is being thrown from within the cmbRecipeType_SelectionChanged event handler. If that's the case, you have two options:

  1. Put a breakpoint inside that method and find out what's throwing the exception. It's probably something simple, like this first line yielding a null value:

    string selectedRecipeType = cmbRecipeType.SelectedItem as string;

If that's true, you could probably whack this in straight after that:

if (selectedRecipeType == null) return;

Which will prevent any subsequent code from accessing selectedRecipeType as if it's non-null.

  1. Do something similar to what I originally suggested, and temporarily unhook that event handler from your ComboBox before you clear the items. Then hook it up again straight after.
于 2009-07-14T09:13:06.823 回答
2

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

myCmbBox.ItemsSource = null;
myCmbBox.ItemsSource = yourLoadMethod();
于 2009-08-26T20:06:07.190 回答