Not able to make cascading comboboxes work - wpf

Here is my code to create cascading comboboxes. I am trying to populate Family Combobox(ComboBox2) based on the value selected for Segment Name(combox1).I am able to populate the first Combo with a static resource but my second one shows blank.
I am calling a method called "FillComboBoxFamilyData(SegmentCode)" on the selection change event of first combobox.
XAML CODE:
<Grid Height="142" HorizontalAlignment="Left" Margin="49,113,0,0" Name="grid3" VerticalAlignment="Top" Width="904">
<ComboBox Height="23" HorizontalAlignment="Left" Margin="35,26,0,0" Name="comboBox1" VerticalAlignment="Top" Width="205" ItemsSource="{Binding Source={StaticResource tblSegmentViewSource}}" DisplayMemberPath="Segment Name" SelectedValuePath="Segment Code" SelectionChanged="comboBox1_SelectionChanged"/>
<ComboBox Height="23" HorizontalAlignment="Right" Margin="0,26,395,0" Name="comboBox2" VerticalAlignment="Top" Width="205" />
<Window.Resources>
<CollectionViewSource x:Key="tblSegmentViewSource" Source="{Binding Path=TblSegment, Source={StaticResource brickDataset}}" />
<CollectionViewSource x:Key="tblFamilyViewSource" Source="{Binding Path=TblFamily, Source={StaticResource brickDataset}}" />
*BrickDataSet is the main dataset I am pulling the tables from.*
C#:
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
MessageBox.Show(comboBox1.SelectedValue.ToString());
SegmentCode = Convert.ToInt32(comboBox1.SelectedValue.ToString());
FillComboBoxFamilyData(SegmentCode);
}
public void FillComboBoxFamilyData(int Segment_Code)
{
string connString =
"Data Source=.\\SQLEXPRESS;AttachDbFilename=C:\\Documents and Settings\\dchaman\\My Documents\\PDRT.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True ";
SqlConnection con = new SqlConnection(connString);
con.Open();
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText =
"SELECT TblFamily.[Family Name],TblFamily.[Family Code] FROM TblFamily WHERE (TblFamily.[Segment Code] = #SegmentCode)";
cmd.Parameters.AddWithValue("#SegmentCode", Segment_Code);
DataSet objDs = new DataSet();
SqlDataAdapter dAdapter = new SqlDataAdapter();
dAdapter.SelectCommand = cmd;
dAdapter.Fill(objDs);
con.Close();
if (objDs.Tables[0].Rows.Count > 0)
{
MessageBox.Show("Here I am");
comboBox2.DataContext = objDs.Tables;
comboBox2.Items.Insert(0, "--Select Family Name--");
comboBox2.DisplayMemberPath = "Family Name";
comboBox2.SelectedValue = "Family Code";
}
}
I am banging my head with the table right now.Please Save me!

You aren't setting the comboBox2's ItemsSource. The DataContext will simply effect all binding statements on it. If you set the ItemsSource to the correct table instead of the DataContext, it should get you on the right path:
if (objDs.Tables[0].Rows.Count > 0)
{
MessageBox.Show("Here I am");
comboBox2.ItemsSource = ((IListSource)objDs.Tables[0]).GetList(); // set the ItemsSource instead of the DataContext
comboBox2.DisplayMemberPath = "Family Name";
comboBox2.SelectedValue = "Family Code";
}
Note that when you set the ItemsSource, the line that inserts text into the Items property will fail, as you can not use both the ItemsSource and the Items together.

Related

WPF DataGrid ComboBoxColumn Not Updating Bound Data

I have a dropdown column in my datagrid, the options for the combobox are stored in the tmfCNCComponentStatus_threed table. My main table has a column called [Status] which corresponds to the key column in that table.
The correct status [Description] is displayed in the combobox for each row in my datagrid, but when the user changes the selection, the database isn't updating, even though everything looks as though it is working properly. I have the "UpdateSourceTrigger" set to PropertyChanged as seen in many similar posts but still no dice. Any insight would be greatly appreciated!
<CollectionViewSource x:Key="StatusItems"/>
<DataGridTemplateColumn x:Name="StatusColumn" Header="Status" Width="*" IsReadOnly="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="cboStatus" Text="{Binding Path=Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="StatusCombo" SelectedValuePath="CNCComponentStatusKey" DisplayMemberPath="Description" SelectedValue="{Binding Status, UpdateSourceTrigger=PropertyChanged}" ItemsSource="{Binding Source={StaticResource StatusItems}}" IsEditable="True" IsSynchronizedWithCurrentItem="True"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
The code behind:
Dim com As String = "SELECT tmfCNCComponent_threed.[CNCComponentKey]
,tmfCNCComponent_threed.[CompanyID]
,tmfCNCComponent_threed.[JobNumber]
,tmfCNCComponent_threed.[LogNumber]
,tmfCNCComponent_threed.[Customer]
,tmfCNCComponent_threed.[DueDate]
,tmfCNCComponent_threed.[JobLeader]
,tmfCNCComponent_threed.[CADProgrammer]
,tmfCNCComponent_threed.[Salesperson]
,tmfCNCComponent_threed.[CNCProgrammer]
,tmfCNCComponent_threed.[ComponentDescription]
,tmfCNCComponent_threed.[ComponentFilePath]
,tmfCNCComponent_threed.[Material]
,tmfCNCComponent_threed.[ComponentSizeX]
,tmfCNCComponent_threed.[ComponentSizeY]
,tmfCNCComponent_threed.[ComponentSizeZ]
,tmfCNCComponent_threed.[QuantityShown]
,tmfCNCComponent_threed.[QuantityMirror]
,tmfCNCComponent_threed.[UpdateTime]
,tmfCNCComponent_threed.[Status]
,tmfCNCComponent_threed.[ProgStarted]
,tmfCNCComponentStatus_threed.[Description]
FROM [test_3DimensionalDB].[dbo].[tmfCNCComponent_threed]
INNER JOIN tmfCNCComponentStatus_threed
ON tmfCNCComponent_threed.Status = tmfCNCComponentStatus_threed.CNCComponentStatusKey
WHERE [ComponentDescription] " & component & " 'trode%' AND [CompanyID]='" & company & "' AND [Status]" & status & "ORDER BY [UpdateTime] DESC"
Dim Adpt As New SqlDataAdapter(com, con)
con.Open()
Dim ds As New DataSet()
Adpt.Fill(ds, "dbo.tmfCNCComponent_threed")
dataGrid1.ItemsSource = ds.Tables("dbo.tmfCNCComponent_threed").DefaultView
con.Close()
con.Open()
Dim statusCVS As CollectionViewSource = FindResource("StatusItems")
Dim com2 As String = "SELECT * FROM tmfCNCComponentStatus_threed"
Dim AdptStatus As New SqlDataAdapter(com2, con)
AdptStatus.Fill(ds, "dbo.tmfCNCComponentStatus_threed")
Dim statusRows = ds.Tables("dbo.tmfCNCComponentStatus_threed").Rows
Dim statuses As New List(Of Object)
For Each row As DataRow In statusRows
statuses.Add(New With {
.Status = CInt(row("CNCComponentStatusKey")),
.Description = CStr(row("Description"))
})
Next
statusCVS.Source = statuses
con.Close()
RowCount()
searchBox.Clear()
Thanks for your time.
The Database:
Contents of the Status table:
The Datagrid:
Here is the first part of this question that was addressed yesterday to get me to this point:
Part 1
Based on information in comments in a different question, you probably need to change SelectedValuePath="Status" to SelectedValuePath="CNCComponentStatusKey". The names of the columns or properties of the items in the combobox are critical to answering this question, and you haven't provided them.
The grid will update the DataRowView column value when the cell leaves edit mode.
Mode=TwoWay on that binding is unnecessary. That's the default mode for bindings on ComboBox.SelectedValue.
You can remove all those decorations from the binding on TextBlock.Text: It can't update the source at all, when you think about it, so there's no need to clutter up your XAML with elaborate instructions about how and when it should do something it can't do anyway.
Complete working example
This is the code with which I tested the above answer. It updates the rows in the main table. It doesn't save the table to a database. That's a separate thing.
I don't know if your columns aren't called what you think they are, or what.
MainWindow.xaml.cs
public MainWindow()
{
InitializeComponent();
LoadData();
}
#region Lists
private static List<String> _status = new List<String>
{
"Ready",
"Not Ready",
"Weary",
"Disordered",
};
private static List<String> _words = new List<String>
{
"Ewwrigowasaus",
"Skubreuph",
"Creecroicr",
"Eunthaudrawtr",
"Ootwoww",
"Meuleetroithr",
"Rewshr",
"Scoysl",
"Scewziexul",
"Kawxayzeec",
};
#endregion Lists
protected void LoadData()
{
DataTable dtMain = new DataTable();
dtMain.Columns.Add("Status", typeof(int));
dtMain.Columns.Add("Programmer", typeof(String));
_words.ForEach(w =>
{
var row = dtMain.NewRow();
row[0] = ((int)w[0] % 2) + 1;
row[1] = w;
dtMain.Rows.Add(row);
});
DataTable dtStatus = new DataTable();
dtStatus.Columns.Add("CNCComponentStatusKey", typeof(int));
dtStatus.Columns.Add("Description", typeof(String));
_status.ForEach(s =>
{
var row = dtStatus.NewRow();
row[0] = dtStatus.Rows.Count + 1;
row[1] = s;
dtStatus.Rows.Add(row);
});
DataGrid.ItemsSource = dtMain.DefaultView;
var cvs = (FindResource("StatusItems") as CollectionViewSource);
cvs.Source = dtStatus.DefaultView;
}
MainWindow.xaml
<Window.Resources>
<CollectionViewSource x:Key="StatusItems" />
</Window.Resources>
<Grid>
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Programmer}" Header="Programmer" />
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Status}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<ComboBox
ItemsSource="{Binding Source={StaticResource StatusItems}}"
SelectedValue="{Binding Status, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Description"
SelectedValuePath="CNCComponentStatusKey"
x:Name="Combo"
/>
<!-- Selected value in combo -->
<Label Content="{Binding SelectedValue, ElementName=Combo}" />
<!-- Value of Status column in row -->
<Label Content="{Binding Status}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>

A simpler way to use DataGridComboBoxColumn?

I have a WPF (.NET 4) DataGrid backed by a DataView from a DataTable, which has as one of its columns a DataGridComboBoxColumn. Everything is working for me, but I had to create a new class to hold the contents of what is a simple [ArrayList/List<string>/whatever IEnumerable I can try] for the possible values of the DGCBC, when it seems like there should be a less-convoluted way. Here is my XAML:
<Window x:Class="MASTableMaint.TruckloadLimitsEdit"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Edit Truckload Limits" Height="600" Width="460" MinWidth="300" MinHeight="300" WindowStartupLocation="CenterOwner" >
<DockPanel LastChildFill="True">
<DataGrid Name="TruckloadGrid" ItemsSource="{Binding}" CanUserReorderColumns="False" CanUserResizeRows="False" CanUserSortColumns="False"
AutoGenerateColumns="False" RowHeaderWidth="20">
<DataGrid.Columns>
<DataGridComboBoxColumn x:Name="companyIdColumn" Header="Company" SelectedValueBinding="{Binding Path=CompanyID}"
DisplayMemberPath="TheCompanyID" SelectedValuePath="TheCompanyID"/>
...
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
And my code behind:
namespace MASTableMaint
{
public partial class TruckloadLimitsEdit : Window
{
private DataTable truckloadDT = new DataTable();
private SqlDataAdapter truckloadDA;
private SqlConnection sqlconn;
public TruckloadLimitsEdit(List<string> massCompanies)
{
sqlconn = new SqlConnection(Constants.SqlConnectionStr);
if (!DbUtils.OpenDbConn(sqlconn))
{
sqlconn.Dispose();
return;
}
string query = "SELECT * FROM tTruckload ORDER BY CompanyID";
truckloadDA = new SqlDataAdapter(query, sqlconn);
truckloadDA.Fill(truckloadDT);
SqlCommandBuilder builder = new SqlCommandBuilder(truckloadDA);
InitializeComponent();
DataView truckloadDV = new DataView(truckloadDT, null, null, DataViewRowState.CurrentRows);
TruckloadGrid.ItemsSource = truckloadDV;
ObservableCollection<MassCompany> ocMassCompanies = new ObservableCollection<MassCompany>();
foreach (string company in massCompanies)
{
ocMasCompanies.Add(new MassCompany(company));
}
companyIdColumn.ItemsSource = ocMassCompanies;
}
...
}
public class MassCompany
{
public MassCompany(string company)
{
TheCompanyID = company;
}
public string TheCompanyID { get; set; }
}
}
It seems that the collection is shared for all rows.
If so, define a dependency property of type ObservableCollection<MassCompany> on your window (we'll call it WinMassCompanies).
Then in constructor:
WinMassCompanies = new ObservableCollection<MassCompany>();
foreach (string company in massCompanies)
{
WinMassCompanies.Add(new MassCompany(company));
}
//don't fiddle with the column
In XAML:
<DataGridComboBoxColumn ItemsSource="{Binding WinMassCompanies,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"
...../>

Cannot modify the logical children for this node at this time because a tree walk is in progress

I have two wpf tool kit charts one is pie chart and second bar series
i have method which i call only on form load
chartGuest.DataContext = null;
List<KeyValuePair<string, int>> valueList = new List<KeyValuePair<string, int>>();
HProDataContext db = new HProDataContext();
var _RoomTypes = (from d in db.roomtypes select d.roomtype1).ToList();
var _RoomTypeID = (from d in db.roomtypes select d.id).ToList();
int count = 0;
for (int i = 0; i < _RoomTypeID.Count; i++)
{
count = Convert.ToInt32((from d in db.actions where d.room.roomtypeid == _RoomTypeID[i] select d.id).Count());
valueList.Add(new KeyValuePair<string, int>(_RoomTypes[i], count));
}
chartGuest.DataContext = valueList;
It gaves such error : Cannot modify the logical children for this node at this time because a tree walk is in progress.
The same code works great on pie series chart.
This is my charts:
<charting:Chart x:Name="chartRoomType" Width="402" Height="255" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="15,275,0,0">
<charting:Chart.Series>
<charting:PieSeries ItemsSource="{Binding}" DependentValuePath="Value" IndependentValuePath="Key" Title="Room Types" IsSelectionEnabled="True" />
</charting:Chart.Series>
</charting:Chart>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="314,292,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="28,296,0,0" Name="textBlock4" Text="Room Types" VerticalAlignment="Top" />
<charting:Chart x:Name="chartGuest" Height="269" VerticalAlignment="Top" Margin="6,0" Title="Guests">
<charting:Chart.Series>
<charting:BarSeries ItemsSource="{Binding}" DependentValuePath="Value" IndependentValuePath="Key" Title="Room Types" IsSelectionEnabled="True" />
</charting:Chart.Series>
</charting:Chart>
Can anyone help me?
P.s. i found this question but it was unhelpful
What does Cannot modify the logical children for this node at this time because a tree walk is in progress mean?
Use DataPointSeries.ItemsSource to bind to the data context.
Assuming that this is XAML of your your window panel that has the datagrid and charting control sharing a common list as ItemsSource..
<StackPanel>
<tk:DataGrid MaxHeight="200" AutoGenerateColumns="False"
ItemsSource="{Binding}"
IsReadOnly="True">
<tk:DataGrid.Columns>
<tk:DataGridTextColumn Header="Key"
Binding="{Binding Key, Mode=OneWay}"/>
<tk:DataGridTextColumn Header="Value"
Binding="{Binding Value, Mode=OneWay}"/>
</tk:DataGrid.Columns>
</tk:DataGrid>
<charting:Chart MaxHeight="300"
Title="Title"
LegendTitle="Legend"
Name="Chart1">
<charting:AreaSeries DependentValuePath="Value"
IndependentValuePath="Key"
Background="Red" >
<charting:DataPointSeries.ItemsSource>
<Binding BindsDirectlyToSource="True"/>
</charting:DataPointSeries.ItemsSource>
</charting:AreaSeries>
</charting:Chart>
<Button Content="Change DataGrid and Chart Data" Click="Button_Click"/>
</StackPanel>
In code behind we reset the data context of the window ....
private List<KeyValuePair<int, int>> list1;
public Window1()
{
InitializeComponent();
list1 = new List<KeyValuePair<int, int>>();
var random = new Random();
for(int i = 0; i < 1000; i++)
{
list1.Add(new KeyValuePair<int, int>(i, random.Next()));
}
this.DataContext = list1;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
list1 = new List<KeyValuePair<int, int>>();
var random = new Random();
for (int i = 0; i < 1000; i++)
{
list1.Add(new KeyValuePair<int, int>(i, random.Next()));
}
this.DataContext = list1;
}
Everytime you click the button the chart refreshes without error.
Let me know if this helps.
I've received the same exception in different situation. I work with code which takes collection of existing UIElements and create new UIElement and set first one as Content of second one. Aditionally, it takes property value from existing UIElement and set it as value of different property of new UIElement.
foreach(UIElement insideElement in uiElementCollection)
{
var outsideElement = new TabItem
{
Content = insideElement
,Header = insideElement.Title
}
}
But in this case Title of inside property can be a Binding, but code above copies only value and when insideElement.Title is bounded to some source, outsideElement.Header doesn't reflect change.
So I changed code to bind HeaderProperty to TitleProperty of insideElement:
foreach(UIElement insideElement in uiElementCollection)
{
var outsideElement = new TabItem
{
Content = insideElement
}
outsideElement.SetBinding(HeaderedContentControl.HeaderProperty,
new Binding
{
Source = insideElement,
Path = new PropertyPath(MyUIElement.TitleProperty)
});
}
But when I executed code above, I received
System.InvalidOperationException: Cannot modify the logical children for this node at this time because a tree walk is in progress.
I found that I can't bind one dependency property to another one, which is stored inside Content property.
I tried to get binding expression of innerUIElement and set it as new binding to HeaderProperty of outsideUIElement.
foreach(UIElement insideElement in uiElementCollection)
{
var outsideElement = new TabItem
{
Content = insideElement
}
BindingExpression titleBindingExpression = pageControl.GetBindingExpression(MyUIElement.TitleProperty);
if (titleBindingExpression != null)
{
tabItem.SetBinding(HeaderedContentControl.HeaderProperty, new Binding { Source = titleBindingExpression.DataItem, Path = titleBindingExpression.ParentBinding.Path });
}
else
{
tabItem.Header = innerUIElement.Title;
}
}
Now, outer UI Element is binded to same source and WPF presenter doesn't throw Exception. My problem is solved.
I know this has been a while, but in case anyone else comes across it I found another way around it. Put the chart into a StackPanel, created with Visibility of "Collapsed" ("Hidden" DOES NOT WORK). Then set visibility to "Visible" after setting DataContext the first time (I'm doing it every time, but after the first it's redundant).
My experience agrees with reports I've seen that the problem is a bug that occurs when setting a non-empty DataContext after having had an empty one; but apparently it doesn't do the "tree walk" if the chart is collapsed.

AutoCompleteBox's Dropdownlist items is not displayed in WPF

I am new to WPF.I have AutoCompleteBox.When i enter a search text,dropdownlist is populated.It contains items.I am able to selected those items and saved into databse through down or up arrow.But items are not visible.Here is my code
<AutoComplete:AutoCompleteBox Background="White" Tag="TagName..." Margin="0,0,28.8,0" Name="txtCustomTagName" BorderBrush="#FF104E8B" FontWeight="Normal" BorderThickness="1,1,0,1" FontSize="14" Foreground="#FF104E8B" TextChanged="txtCustomTagName_TextChanged" LostFocus="txtCustomTagName_LostFocus" PreviewTextInput="txtCustomTagName_PreviewTextInput" Populating="txtCustomTagName_Populating" >
<AutoComplete:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<TextBlock />
</DataTemplate>
</AutoComplete:AutoCompleteBox.ItemTemplate>
</AutoComplete:AutoCompleteBox>
//Populated Event:-
private void txtCustomTagName_Populating(object sender, PopulatingEventArgs e)
{
string strFilePath = "";
string strNewFile = "";
strFilePath += #"../../FIXDictionaries/";
string typedString = txtCustomTagName.Text; ;
strNewFile = strFilePath + cmbFIXVerDataDictionary.Text + extension;
XDocument xmldoc = XDocument.Load(strNewFile);
List<string> tags = new List<string>();
IEnumerable<string> childNames = (from child in xmldoc.Element("fix").Element("fields").Descendants("field")
select child.Attribute("name").Value).Distinct().ToList();
foreach (string childName in childNames)
{
if (childName.StartsWith(typedString, StringComparison.InvariantCultureIgnoreCase))
{
tags.Add(childName);
}
}
txtCustomTagName.ItemsSource = tags;
}
}
How to do it?
I suppose the cause is you use ItemTemplate with empty TextBlock. Or don't use ItemTemplate at all or (in your case) replase it with <TextBlock Text="{Binding}" />

how to optimize the performance of a wpf application

i make a wpf application its running well.but whenever the size of my xml is to big its running very slow every time we fetch data from xml as code below
is any body suggest me it is because of this or may be other problem
how can i reform this
thanks
shashank`
DataSet xmlData = new DataSet();
XmlTextReader reader = null;
try
{
if (File.Exists(CommonUtils.xmlPath))
{
//convert XmlDocument to XmlTextReader
reader = new XmlTextReader(new StringReader(CommonUtils.DecryptXML().OuterXml));
//get the xml data
xmlData.ReadXml(reader);
reader.Close();
//get category rows from
DataRow[] eventRows = xmlData.Tables["M_EVENT"].Select(" ROW_STATUS=1");
if (eventRows.Length > 0)
{
//create a datatable for event
DataTable dtEvent = xmlData.Tables["M_EVENT"].Clone();
//add a default row to the event table
DataRow dr = dtEvent.NewRow();
dr[0] = "-1";
dr[1] = "--Select Event--";
dr[2] = "1";
dtEvent.Rows.InsertAt(dr, 0);
foreach (DataRow row in eventRows)
{
DataRow drEvent = dtEvent.NewRow();
drEvent["PK_EVENT_ID"] = row["PK_EVENT_ID"];
drEvent["EVENT_NAME"] = row["EVENT_NAME"];
drEvent["EVENT_TYPE"] = row["EVENT_TYPE"];
dtEvent.Rows.Add(drEvent);
}
//bind the category drop down
cmbEvent.DataContext = dtEvent.DefaultView;
cmbEvent.SelectedValuePath = "PK_EVENT_ID";
cmbEvent.DisplayMemberPath = "EVENT_NAME";
cmbEvent.SelectedIndex = 0;
}
}
else
{
Lblgetevent.Visibility = Visibility.Visible;
}
}`
Ouch!
What are you using DataTable for?! It is terribly inefficient for this purpose and requires you to write lots of extra code. Also, why are you setting ComboBox properties from code and not in XAML?
A much, much simpler way is to bind your ComboBox directly to the XML:
<ComboBox ItemsSource="{Binding EventXml, XPath=M_EVENT[ROW_STATUS=1]}"
...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding XPath=EVENT_NAME}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
This is better than the DataTable technique, but to add your "Select Event" row will require a CompositeCollection to be added. That can be done, but...
The best solution is to use LINQ to XML:
public object Events
{
get
{
return new[] { new { Name = "--Select Event--", Id = -1 }}.Concat(
from element in EventsXml.Elements("M_EVENT")
where element.Element("ROW_STATUS").Value=="1"
select new
{
Name = element.Element("EVENT_NAME").Value,
Id = int.Parse(element.Element("PK_EVENT_ID").Value),
});
}
}
With this simple XAML:
<ComboBox ItemsSource="{Binding Events}" SelectedValuePath="Id" ...>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The LINQ to XML solution is faster than binding to XML, which in turn is faster than using DataTable. Not only that, but the LINQ to XML solution is much cleaner than the other two.

Resources