I'm trying to create an edit form for editing properties of a custom set of TV Series objects. One of the properties holds a collection of all owned media formats (DVD, Blu-ray, etc) for that particular series that will be displayed in a ComboBox. Items are added to the ComboBox via a separate popup window and items are to be removed from the ComboBox by selecting the item and clicking a remove Button.
I can add new entries to the MediaOwned ComboBox just fine, but when I try to select a specific ComboBox item to test the remove Button I find that I can only ever select the first entry. Can someone please tell me if I've missed something embarrassingly obvious, thanks.
Here is the problematic property:
private ObservableCollection<string> _mediaOwned = new ObservableCollection<string>();
public ObservableCollection<string> MediaOwned
{
get { return _mediaOwned; }
set
{
_mediaOwned = value;
OnPropertyChanged(new PropertyChangedEventArgs("MediaOwned"));
}
}
Here are the other relevant code behind:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Create binding for the ListBox.
Binding listBinding = new Binding();
listBinding.Source = show.Series;
listBinding.Mode = BindingMode.OneWay;
listBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
lbSeries.SetBinding(ListBox.ItemsSourceProperty, listBinding);
// Create binding for the ComboBox.
Binding myBinding = new Binding();
myBinding.Path = new PropertyPath("MediaOwned");
myBinding.Mode = BindingMode.TwoWay;
myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
cbMediaOwned.SetBinding(ComboBox.ItemsSourceProperty, myBinding);
}
private void btnRemoveMedia_Click(object sender, RoutedEventArgs e)
{
Series series = (Series)lbSeries.SelectedItem;
series.MediaOwned.Remove(cbMediaOwned.Text);
}
And here is the XAML code:
<Border Style="{StaticResource PanelBorderStyle}" DockPanel.Dock="Left" Margin="0,8,8,0"
DataContext="{Binding ElementName=lbLists, Path=SelectedItem}">
<DockPanel VerticalAlignment="Top">
<StackPanel>
<ListBox x:Name="lbSeries" Style="{StaticResource BasicListStyle}" Width="180" Height="300"
DisplayMemberPath="Title" SelectionMode="Single" LayoutUpdated="lbSeries_LayoutUpdated">
</ListBox>
</StackPanel>
<StackPanel x:Name="editPanel" DataContext="{Binding ElementName=lbSeries, Path=SelectedItem}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="0, 4, 0, 0">
<TextBlock Style="{StaticResource SmallFont}" Width="100">Title</TextBlock>
<TextBox x:Name="txtTitle" Style="{StaticResource TextBoxStyle}" Text="{Binding Path=Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="8, 8, 16, 8"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock Style="{StaticResource SmallFont}" Width="100">Media owned</TextBlock>
<ComboBox x:Name="cbMediaOwned" Style="{StaticResource ComboBoxStyle}" Width="150" Margin="8,8,6,8"
></ComboBox>
<Button x:Name="btnAddMedia" Style="{StaticResource ToolbarButtonStyle}" Click="btnAddMedia_Click" Margin="0">
<StackPanel ToolTip="Add media">
<Image Source="Images/add.png" />
</StackPanel>
</Button>
<Button x:Name="btnRemoveMedia" Style="{StaticResource ToolbarButtonStyle}" Click="btnRemoveMedia_Click" Margin="4">
<StackPanel ToolTip="Remove media">
<Image Source="Images/remove.png" />
</StackPanel>
</Button>
</StackPanel>
</StackPanel>
</DockPanel>
</Border>
Alternatively I can also remove the binding code in the code behind and replace the ComboBox with the below code (but I still get the same problem - I can't select anything in the ComboBox):
<ComboBox x:Name="cbMediaOwned" Style="{StaticResource ComboBoxStyle}" Width="150" Margin="8,8,6,8" ItemsSource="{Binding ElementName=lbSeries, Path=SelectedItem.MediaOwned, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedMedia, UpdateSourceTrigger=PropertyChanged}"></ComboBox>
SelectedMedia property:
private string _selectedMedia = "";
public string SelectedMedia
{
get { return _selectedMedia; }
set
{
_selectedMedia = value;
OnPropertyChanged(new PropertyChangedEventArgs("SelectedMedia"));
}
}
Here is my xaml:
<ComboBox x:Name="Models_ComboBox"
Width="110"
Text="Model"
ItemsSource="{Binding Models}"
SelectedItem="{Binding SelectedModel}"
DisplayMemberPath="Model"
MouseDoubleClick="Models_ComboBox_MouseDoubleClick"
SelectionChanged="Models_ComboBox_SelectionChanged"/>
Here are my VM properties:
private DataTable models;
public DataTable Models
{
get { return models; }
set
{
if (models != value)
{
models = value;
OnPropertyChanged(nameof(Models));
}
}
}
and
private DataRowView selectedModel;
public DataRowView SelectedModel
{
get { return selectedModel; }
set
{
if (selectedModel != value)
{
selectedModel = value;
if (value != null)
{
InitializeOptions(value["Model"].ToString());
}
OnPropertyChanged(nameof(SelectedModel));
}
}
}
As you can see, the ItemsSource and the SelectedItem of the ComboBox are bound to two different properties in the ViewModel. The ItemsSource is bound to a DataTable populated from a Database. Once the user selects a Model, then there are other option ComboBoxes that are populated based on that selection.
Fixed the problem myself. I had a line of code that was automatically setting the SelectedIndex of the ComboBox without me realizing.
I am working on a C# UWP assignment and I have a listview displaying information from a database. I want to show a list of orders, and each row has an orderID and a button to delete the order (which will delete it from the database). I though I could use a x:Name="orderid" and just pull that value in my function but it isn't recognizing it in the c# code.
.xaml.cs file includes:
Order o = new Order();
OrderList.ItemsSource = o.GetProducts(user);
.xaml (removed other columns for sake of example):
<RelativePanel Grid.Row="4" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="7" HorizontalAlignment="Center">
<ListView Name="OrderList"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.IsVerticalRailEnabled="True"
ScrollViewer.VerticalScrollMode="Enabled"
ScrollViewer.HorizontalScrollMode="Enabled"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.IsHorizontalRailEnabled="True"
Margin="20">
<ListView.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Text="ID" Margin="8,0" Width="50" Foreground="DarkRed" />
<TextBlock Text="Date" Width="200" Foreground="DarkRed" />
<TextBlock Text="Delete" Width="50"/>
</StackPanel>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Order">
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="orderid"
Text="{x:Bind OrderID}"
Width="50" />
<TextBlock Name="orderdate"
Text="{x:Bind OrderDate}"
Width="200" />
<Button Content="X" Click="Button_Click"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</RelativePanel>
C# (Order Class - OrderID etc are all properties):
public ObservableCollection<Order> GetProducts(User user)
{
const string GetOrdersQuery = "select * from orders";
var orders = new ObservableCollection<Order>();
try
{
using (SqlConnection conn = new SqlConnection(user.ConnectionString))
{
conn.Open();
if (conn.State == System.Data.ConnectionState.Open)
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = GetOrdersQuery;
using (SqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var order = new Order();
order.OrderID = (int)reader["orderID"];
order.OrderDate = (DateTime)reader["orderDate"];
order.MethodOfDelivery = (string)reader["methodOfDelivery"];
order.DeliveryAddress = (reader["deliveryAddress"] as string);
order.MethodOfPayment = (string)reader["methodOfPayment"];
order.CardUsed = (reader["cardNumber"] as string);
order.Subtotal = (decimal)reader["subtotal"];
order.Discount = (decimal)reader["discountPercentage"];
order.Tax = (decimal)reader["tax"];
order.OrderTotal = (decimal)reader["orderTotal"];
order.CustID = (reader["custID"] as int?) ?? 0;
orders.Add(order);
}
}
}
}
}
return orders;
}
catch (Exception eSql)
{
Debug.WriteLine("Exception: " + eSql.Message);
}
return null;
}
and then I wanted to make a function in the xaml.cs file that would grab that row's orderID, and make a query to delete the order based on the id, but doing orderid.Text won't work here for some reason.
Any suggestions/help would be much appreciated!
If my code is a little all over the place it's because I'm fairly new to this!
One possible solution is to bind the "OrderId" to the "Tag" attribute in your Button element.
<Button Content="X" Click="Button_Click" Tag="{Binding Id}"/>
After the bind, in your Event handler for Click you call a method to remove it from database and from your ObservableCollection, something like:
private void Button_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
{
var button = sender as Button;
_viewModel.DeleteOrder((int)button.Tag);
}
My DeleteOrder method is simple:
private ObservableCollection<Order> _orders;
public ObservableCollection<Order> Orders
{
get { return _orders; }
set { _orders = value; OnChange(); }
}
public void DeleteOrder(int id)
{
var order = Orders.FirstOrDefault(o => o.Id == id);
if (order != null)
{
Orders.Remove(order);
}
}
I have a custom input dialog box that request an user's name and a reson (because reasons) for doing a certain action in my application. The user clicks on a button on the main window and the dialog box shows, as it should.
The user then enters his/her name and the reason and clicks ok. The dialog then closes but I ( the program) never receives an answer. Here is my XAML for the input dialog:
<Window x:Class="Sequence_Application_2.GUI.ForcedRackInput"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Forcera Rack" Height="300" Width="300"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="21*"/>
<ColumnDefinition Width="274*"/>
</Grid.ColumnDefinitions>
<TextBox Name="OperatorNameText" HorizontalAlignment="Left" Height="23" Margin="15,36,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Grid.ColumnSpan="2"/>
<Label x:Name="label" Content="Namn:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2"/>
<Label x:Name="label1" Content="Orsak:" HorizontalAlignment="Left" Margin="10,72,0,0" VerticalAlignment="Top" Grid.ColumnSpan="2"/>
<Border BorderThickness="1" BorderBrush="Black" Grid.ColumnSpan="2" Margin="0,0,0,0.5">
<TextBox Name="ReasonText" Margin="15,98,15,0" TextWrapping="Wrap" VerticalAlignment="Top" Height="116" />
</Border>
<Button Name="OkButton" IsDefault="True" Content="OK" Click="OkButtonPressed" HorizontalAlignment="Left" Margin="26.202,233,0,0" VerticalAlignment="Top" Width="75" Cursor="Arrow" Grid.Column="1"/>
<Button Name="CancelButton" IsCancel="True" Content="Avbryt" Margin="152.202,233,47,0" VerticalAlignment="Top" Cursor="Arrow" Grid.Column="1"/>
</Grid>
</Window>
And here is the "behind code":
namespace Sequence_Application_2.GUI
{
using System.Windows;
public partial class ForcedRackInput : Window
{
public string OperatorName { get { return OperatorNameText.Text; } }
public string ForcedRackReason { get { return ReasonText.Text; } }
public ForcedRackInput()
{
InitializeComponent();
}
private void OkButtonPressed(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
}
}
}
and this is how I call the code (from a model, not a "window class")
public void ForceClosingRack(Flow forcedFlow)
{
var forcedRackWindow = new ForcedRackInput();
string operatorName = "";
string reasonForForced = "";
if( forcedRackWindow.ShowDialog() == true)
{
operatorName = forcedRackWindow.OperatorName;
reasonForForced = forcedRackWindow.ForcedRackReason;
}
} // code jumps from "if(forcedRackWindow.... to this line when ok is clicked in the dialog
Looked for the solution for some time now and I just about to change career
Thanks for your time
My guess is that the problem doesn't lie in the code, which seems to be fine, but in your if statement.
When you run your program in Debug mode it should work as expected.
My guess is that you are assigning the variables operatorName and reasonForForced inside your if statment but they are not used anywhere else in the program and hence the whole if statement is ignored by the compiler and not present when running in Release mode.
A small modification in your code which embeds different behaviour depending on the variable values can prove my guess:
private void Button_Click(object sender, RoutedEventArgs e)
{
var forcedRackWindow = new ForcedWindow();
string operatorName = "foo";
string reasonForForced = "foo";
if (forcedRackWindow.ShowDialog() == true)
{
operatorName = forcedRackWindow.OperatorName;
reasonForForced = forcedRackWindow.ForcedRackReason;
}
if(!operatorName.Equals(reasonForForced))
{
MessageBox.Show("We are not the same");
}
}
So I am hoping to alter my program such that I can run a function to check and see if the foreground color should be black or silver. I am hoping to gray out fields that are not "accessible".
My form currently looks like:
I was hoping to "gray out" the "No maintenance required" fields. But I am having problems with trying to define a binding element to the font foreground in my data template.
I've tried everything from trying to define an IValueConverter class within the main window code behind, to defining a window key resource, but it doesn't appear that I can do that within a data template on the textblock element itself?
Any suggestions/help would be appreciated. Thanks!
XAML:
<Grid Margin="0,0,2,0">
<ListBox x:Name="allSites_LB"
HorizontalAlignment="Left"
Height="400"
Margin="20,60,0,0"
VerticalAlignment="Top"
Width="945"
Loaded="allSites_LB_Loaded"
BorderThickness="1" SelectionChanged="allSites_LB_SelectionChanged"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
>
<ListBox.ItemTemplate >
<DataTemplate >
<Border BorderBrush="Black" BorderThickness="0,0,0,1" Margin="-20,1,0,1" Padding="0,5,0,5" >
<Grid Margin="75,3" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="400" />
<ColumnDefinition Width="345" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding SiteNo}" Grid.Column="0" FontSize="16" />
<TextBlock Text="{Binding Address}" Grid.Column="1" FontSize="16" Margin="50,1" />
<TextBlock Text="{Binding MaintStatus}" Grid.Column="2" FontSize="16" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="viewHistory_BTN"
Content="View History"
HorizontalAlignment="Left"
Height="52"
Margin="20,496,0,0"
VerticalAlignment="Top"
Width="172" FontSize="20"
/>
<Button x:Name="startMaintenance_BTN"
Content="Start Maintenance"
HorizontalAlignment="Left"
Height="52"
Margin="793,496,0,0"
VerticalAlignment="Top"
Width="172" FontSize="20"
/>
<TextBox x:Name="Site_Address"
HorizontalAlignment="Left"
Height="21"
Margin="51,39,0,0"
TextWrapping="Wrap"
Text="Site Number"
VerticalAlignment="Top"
Width="75"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
<TextBox x:Name="Address_Title"
HorizontalAlignment="Left"
Height="21"
Margin="380,34,0,0"
TextWrapping="Wrap"
Text="Address"
VerticalAlignment="Top"
Width="75"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
<TextBox x:Name="maint_Title"
HorizontalAlignment="Left"
Height="21"
Margin="699,34,0,0"
TextWrapping="Wrap"
Text="Maintenance Record"
VerticalAlignment="Top"
Width="117"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
</Grid>
C# Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Data.SqlClient;
namespace SiteMaintenance
{
public partial class MainWindow : Window
{
/**
* CLASS VARIABLES
* */
private SqlConnection localdbConnection; // Connection to Site Maintenance DB (LOCAL)
private System.Data.DataSet allSitesResults;
// MAIN THREAD
public MainWindow()
{
InitializeComponent();
// try to open SQL Connection
try {
localdbConnection = new SqlConnection(Properties.Settings.Default.localdb);
localdbConnection.Open();
} catch(Exception ex) {
System.Windows.MessageBox.Show("local SQL connection unable to connect");
return;
}
viewHistory_BTN.IsEnabled = false;
startMaintenance_BTN.IsEnabled = false;
startMaintenance_BTN.IsDefault = true;
}
/**
* Load dataset into datagrid
* LAZY LOADING
* */
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
// init command object
SqlCommand myCommand = new SqlCommand();
myCommand.CommandText = "dbo.usp_GetSites";
myCommand.CommandType = System.Data.CommandType.StoredProcedure;
myCommand.Connection = localdbConnection;
// init data adaptor
SqlDataAdapter sites = new SqlDataAdapter();
sites.SelectCommand = myCommand;
//init DataSet
allSitesResults = new System.Data.DataSet();
sites.Fill(allSitesResults, "tblSites");
int tableCount = allSitesResults.Tables.Count;
System.Data.DataTable test = allSitesResults.Tables[0];
int rowCount = test.Rows.Count;
}
private void sites_DG_CurrentCellChanged(object sender, EventArgs e)
{
String siteName = allSitesResults.Tables[0].Rows[0][1].ToString();
}
private void allSites_LB_Loaded(object sender, RoutedEventArgs e)
{
// init command object
SqlCommand myCommand = new SqlCommand();
myCommand.CommandText = "dbo.usp_GetSitesANDCompletedDate";
myCommand.CommandType = System.Data.CommandType.StoredProcedure;
myCommand.Connection = localdbConnection;
// init data adaptor
SqlDataAdapter sites = new SqlDataAdapter();
sites.SelectCommand = myCommand;
//init DataSet
allSitesResults = new System.Data.DataSet();
sites.Fill(allSitesResults, "tblSites");
allSites_LB.ItemsSource = allSitesResults.Tables["tblSites"].DefaultView;
}
// do not allow selection of maintenance records that do not exist
private void allSites_LB_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// grab the index
int selectedIndex = allSites_LB.SelectedIndex;
if (selectedIndex == -1) return; //WITHOUT THIS CHECK, UN-SELECTION WILL CAUSE LOGIC FAILURE
System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];
// grab the completed date field
String completedDate = tempData["CompletedDate"].ToString();
String siteMaintID = tempData["SiteMaintID"].ToString();
// remove selected index if completed date and site Maint ID is null
if (siteMaintID != "" && completedDate == "")
{
startMaintenance_BTN.IsEnabled = true;
}
else
{
allSites_LB.SelectedIndex = -1;
startMaintenance_BTN.IsEnabled = false;
}
}
private String maintRequired(object sender, SelectionChangedEventArgs e)
{
int selectedIndex = allSites_LB.SelectedIndex;
if (selectedIndex < 0) return null;
System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];
// grab the completed date field
String completedDate = tempData["CompletedDate"].ToString();
String siteMaintID = tempData["SiteMaintID"].ToString();
if (siteMaintID != "" && completedDate == "")
{
return "Maintenance Required";
}
else
{
return "No Maintenance";
}
}
}
}
There are generally two good approaches for you to choose from, when binding the Foreground color to a piece of data. Depending on who you ask, different people will have different preferences. So... here's both!
First Method: Style with Triggers
This method basically identifies 'special' behavior when a certain set of conditions are met. In this case, we're changing the foreground color to Gray, when the status == "No Maintenance Required"
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black" /> <!-- default value -->
<Style.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}" Value="No Maintenance Required">
<Setter Property="Foreground" Value="Gray" /> <!-- special behavior -->
</DataTrigger>
</Style.Triggers>
</Style>
In this case, just assign your TextBlock the appropriate Style property.
Second Method: Use an IValueConverter
This approach creates a custom "IValueConverter implementation, which converts your Text value to a Color. From there, we bind directly to our text value, and ensure that the converter always provides the proper color.
public class MaintenaceColorConverter : IValueConverter
{
public Color NormalColor { get; set; }
public Color NoMaintenanceRequiredColor { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.ToString() == "No Maintenance Required")
return NoMaintenanceRequiredColor;
return NormalColor;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In your XAML:
<Window.Resources>
<local:MaintenaceColorConverter x:Key="myColorConverter" NormalColor="Black" NoMaintenanceRequiredColor="Gray" />
</Window.Resources>
In your TextBlock:
<TextBlock Text="{Binding MaintStatus}" Foreground="{Binding MaintStatus, Converter={StaticResource myColorConverter}}" />
Improvements
With either of these approaches, it would be better to have a MaintenanceStatus boolean or enum value, and bind your styling conditions to that. It's a bad idea to use string-comparisons. That's just begging for trouble. These examples used string comparison because... well... that's all that was available from your provided example code.
More than you asked for but this is from some existing code
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsMaintenance}" Value="True">
<Setter Property="Background" Value="Gainsboro" />
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
<Trigger Property="IsSelected" Value="True" >
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
Thanks for the feedback! I went with BTownTKD's suggestion on implementing an IValueConverter although with some alterations in my code. I discovered I needed to define "local" scope in my window properties in XAML.
Also, I was discovering that the binding wasn't actually changing the text color. After stepping through the code and seeing that the method was being properly invoked, I then hardcoded the results returned into the XAML to make sure they were working (foreground="black" or foreground="#FF00000"). I noticed when stepping through the code that the return object was a "color" object in the original binding, and by me hard-coding the colors into the XAML, they were actually strings. So I altered the code slightly to add in a .ToString() to the object I was returning and VOILA it worked! Thanks again for the help!
FYI here's the updated code bits:
XAML:
<Window x:Class="SiteMaintenance.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SiteMaintenance"
Title="MainWindow"
Height="600"
Width="1000">
<Window.Resources>
<local:MaintenenceColorConverter x:Key="MyColorConverter" NormalColor="Black" NoMaintenanceRequiredColor="Gray" />
</Window.Resources>
<Grid Margin="0,0,2,0">
<ListBox x:Name="allSites_LB"
HorizontalAlignment="Left"
Height="400"
Margin="20,60,0,0"
VerticalAlignment="Top"
Width="945"
Loaded="allSites_LB_Loaded"
BorderThickness="1" SelectionChanged="allSites_LB_SelectionChanged"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
>
<ListBox.ItemTemplate >
<DataTemplate >
<Border BorderBrush="Black" BorderThickness="0,0,0,1" Margin="-20,1,0,1" Padding="0,5,0,5" >
<Grid Margin="75,3" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="400" />
<ColumnDefinition Width="345" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding SiteNo}" Grid.Column="0" FontSize="16" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}" />
<TextBlock Text="{Binding Address}" Grid.Column="1" FontSize="16" Margin="50,1" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}" />
<TextBlock Text="{Binding MaintStatus}" Grid.Column="2" FontSize="16" Foreground="{Binding MaintStatus, Converter={StaticResource MyColorConverter}}" />
</Grid>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button x:Name="viewHistory_BTN"
Content="View History"
HorizontalAlignment="Left"
Height="52"
Margin="20,496,0,0"
VerticalAlignment="Top"
Width="172" FontSize="20"
/>
<Button x:Name="startMaintenance_BTN"
Content="Start Maintenance"
HorizontalAlignment="Left"
Height="52"
Margin="793,496,0,0"
VerticalAlignment="Top"
Width="172" FontSize="20"
/>
<TextBox x:Name="Site_Address"
HorizontalAlignment="Left"
Height="21"
Margin="51,39,0,0"
TextWrapping="Wrap"
Text="Site Number"
VerticalAlignment="Top"
Width="75"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
<TextBox x:Name="Address_Title"
HorizontalAlignment="Left"
Height="21"
Margin="380,34,0,0"
TextWrapping="Wrap"
Text="Address"
VerticalAlignment="Top"
Width="75"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
<TextBox x:Name="maint_Title"
HorizontalAlignment="Left"
Height="21"
Margin="699,34,0,0"
TextWrapping="Wrap"
Text="Maintenance Record"
VerticalAlignment="Top"
Width="117"
BorderBrush="White"
IsReadOnly="True"
IsEnabled="False"
/>
</Grid>
</Window>
C# Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
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.Data.SqlClient;
namespace SiteMaintenance
{
public partial class MainWindow : Window
{
/**
* CLASS VARIABLES
* */
private SqlConnection localdbConnection; // Connection to Site Maintenance DB (LOCAL)
private System.Data.DataSet allSitesResults;
// MAIN THREAD
public MainWindow()
{
InitializeComponent();
// try to open SQL Connection
try {
localdbConnection = new SqlConnection(Properties.Settings.Default.localdb);
localdbConnection.Open();
} catch(Exception ex) {
System.Windows.MessageBox.Show("local SQL connection unable to connect");
return;
}
viewHistory_BTN.IsEnabled = false;
startMaintenance_BTN.IsEnabled = false;
startMaintenance_BTN.IsDefault = true;
}
/**
* Load dataset into datagrid
* LAZY LOADING
* */
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
// init command object
SqlCommand myCommand = new SqlCommand();
myCommand.CommandText = "dbo.usp_GetSites";
myCommand.CommandType = System.Data.CommandType.StoredProcedure;
myCommand.Connection = localdbConnection;
// init data adaptor
SqlDataAdapter sites = new SqlDataAdapter();
sites.SelectCommand = myCommand;
//init DataSet
allSitesResults = new System.Data.DataSet();
sites.Fill(allSitesResults, "tblSites");
int tableCount = allSitesResults.Tables.Count;
System.Data.DataTable test = allSitesResults.Tables[0];
int rowCount = test.Rows.Count;
}
private void sites_DG_CurrentCellChanged(object sender, EventArgs e)
{
String siteName = allSitesResults.Tables[0].Rows[0][1].ToString();
}
private void allSites_LB_Loaded(object sender, RoutedEventArgs e)
{
// init command object
SqlCommand myCommand = new SqlCommand();
myCommand.CommandText = "dbo.usp_GetSitesANDCompletedDate";
myCommand.CommandType = System.Data.CommandType.StoredProcedure;
myCommand.Connection = localdbConnection;
// init data adaptor
SqlDataAdapter sites = new SqlDataAdapter();
sites.SelectCommand = myCommand;
//init DataSet
allSitesResults = new System.Data.DataSet();
sites.Fill(allSitesResults, "tblSites");
allSites_LB.ItemsSource = allSitesResults.Tables["tblSites"].DefaultView;
}
// do not allow selection of maintenance records that do not exist
private void allSites_LB_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// grab the index
int selectedIndex = allSites_LB.SelectedIndex;
if (selectedIndex == -1) return; //WITHOUT THIS CHECK, UN-SELECTION WILL CAUSE LOGIC FAILURE
System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];
// grab the completed date field
String completedDate = tempData["CompletedDate"].ToString();
String siteMaintID = tempData["SiteMaintID"].ToString();
// remove selected index if completed date and site Maint ID is null
if (siteMaintID != "" && completedDate == "")
{
startMaintenance_BTN.IsEnabled = true;
}
else
{
allSites_LB.SelectedIndex = -1;
startMaintenance_BTN.IsEnabled = false;
}
}
private String maintRequired(object sender, SelectionChangedEventArgs e)
{
int selectedIndex = allSites_LB.SelectedIndex;
if (selectedIndex < 0) return null;
System.Data.DataRowView tempData = (System.Data.DataRowView)allSites_LB.Items[allSites_LB.SelectedIndex];
// grab the completed date field
String completedDate = tempData["CompletedDate"].ToString();
String siteMaintID = tempData["SiteMaintID"].ToString();
if (siteMaintID != "" && completedDate == "")
{
return "Maintenance Required";
}
else
{
return "No Maintenance";
}
}
}
public class MaintenenceColorConverter : IValueConverter
{
public Color NormalColor { get; set; }
public Color NoMaintenanceRequiredColor { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.ToString() == "No Maintenance Required") return NoMaintenanceRequiredColor.ToString();
return NormalColor.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
I'll be cleaning up my code later with BTown's optimization, but at least its working!
I want to search the name in the list box. I am using MVVM pattern in my application.
My Xaml coding for Listbox
<ListBox Height="440" Background="Azure" ItemsSource="{Binding Content,Mode=TwoWay}" HorizontalAlignment="Left" Margin="0,230,0,0" Name="OutGoingInvitationList" VerticalAlignment="Top" Width="468" BorderBrush="#00565353" SelectionChanged="listBox1_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Name="ListPersonImage" Source="{Binding ListImage}" Height="100" Width="100" Stretch="Uniform" Margin="10,2,0,0" ImageFailed="Image_ImageFailed" />
<TextBlock Text="{Binding ListFullName}" Name="ListPersonFullName" Width="200" Foreground="Black" Margin="10,10,0,0" FontWeight="SemiBold" FontSize="22" />
<TextBlock Text="{Binding ListBio}" Name="ListPersonBio" FlowDirection="LeftToRight" Foreground="Black" Margin="-200,50,0,0" FontWeight="ExtraLight" FontSize="20" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here Content have all the list values.
Now it shows the result. Now i want search the person name. I want to write the code in
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
}
Is it possible to search the names in the listbox. Here i want only show the items in Listbox searched items only. Sorry for the poor English.
Please tell me how to perform this action.
Thanks in advance..
My View Model:
invitationsButton = new ReactiveAsyncCommand();
var invitationResults = invitationsButton.RegisterAsyncObservable(_ =>
{
return HTTPServices.postAndGetResponse((new PersonSearchOperation().GetInvitations(ServiceConstants.Identity_Number)));
});
invitationResults.Subscribe(
x =>
{
ServiceModel sm = new ServiceModel();
Content = new List<ListContactsModel>();
Content1 = new List<ListContactsModel>();
ServiceConstants.Temp_Response = x;
List<ListContactsModel> result = ListContactsModel.extract(x, sm, OutGoingInvitation);
if (!((string.IsNullOrEmpty(sm.NetErrorCode)) && (string.IsNullOrEmpty(sm.ProvResErrCode))))
{
string errCode = !string.IsNullOrEmpty(sm.NetErrorCode) ? sm.NetErrorCode : sm.ProvResErrCode;
string errDesc = !string.IsNullOrEmpty(sm.NetErrorDesc) ? sm.NetErrorDesc : sm.ProvResErrDesc;
MessageBox.Show(errCode + "/" + errDesc);
}
else if (result.Count > 0)
{
Content.AddRange(result);//Outgoing Invitations
}
else
{
MessageBox.Show("There is No Invitations For You"); //Use Resource Bundle
}
}
);
Now Content have all the result.
Please tell me now where i have to implement Search operation?
Actually i have no idea where i have to write the Search Operation Code??
In My view Model I have add this code. I can see the output in Console Window. But UI is not updating.
public void SearchMethod(String searchValue)
{
Console.WriteLine("searchValue...." + searchValue);
Console.WriteLine("ServiceConstants.Temp_Response ...." + ServiceConstants.Temp_Response);
AppGlobalConstants.Temp_SearchValue = searchValue;
ServiceModel sm = new ServiceModel();
Content = new List<ListContactsModel>();
List<ListContactsModel> result = ListContactsModel.extract(ServiceConstants.Temp_Response, sm, OutGoingInvitation);
if (!((string.IsNullOrEmpty(sm.NetErrorCode)) && (string.IsNullOrEmpty(sm.ProvResErrCode))))
{
string errCode = !string.IsNullOrEmpty(sm.NetErrorCode) ? sm.NetErrorCode : sm.ProvResErrCode;
string errDesc = !string.IsNullOrEmpty(sm.NetErrorDesc) ? sm.NetErrorDesc : sm.ProvResErrDesc;
MessageBox.Show(errCode + "/" + errDesc);
}
else if (result.Count > 0)
{
Content.AddRange(result);
Console.WriteLine("Content.Count==>>" + Content.Count);
}
}
In My CS file
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
listContactsViewModel.SearchMethod(userIDTextBox.Text);
}
Sorry. I am very new to windows phone application development. In fact this is my very first project. That's why i don't have any idea. Please tell me where i have to make changes??
In your ViewModel you should have a private collection to hold the orignal list while you can set the search result in content.
In your viewmodel
private List<YourClass> orignalList;
public void Search(string query)
{
// do your query
List<YourClass> list = get...;
// clear content
Content.Clear();
foreach(var item in list)
{
Content.Add(item)
}
}
If you clear the query, you use the orignalList to fill Content.
Remember to set Content as ObservableCollection