Window.ShowDialog failes on return - c#

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

Related

WPF: How to autoreset/autorefresh the textbox after scanning barcode in WPF?

I'm making a simple WPF program where the user will basically only need to scan the barcode using a USB barcode scanner and the program will send the data straight to the cloud ERP. Right now, the program works, but the user has to manually click the textbox after scanning, clear the data and scan again. I just want the user to open the software and just keep on scanning using his barcode reader without having to manually erase the textbox data. How can I do that?
<Window x:Class="ProductionScanner.MainWindow"
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"
xmlns:viewModel="clr-namespace:ProductionScanner.MVVM.ViewModel"
xmlns:local="clr-namespace:ProductionScanner"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Background="#181735" >
<Window.DataContext>
<viewModel:ReceiptViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Background="#0F0F2D"
Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Foods"
Foreground="White"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Left"
/>
<TextBlock Text="Records"
Foreground="White"
Grid.Column="2"
VerticalAlignment="Center"
HorizontalAlignment="Center"
/>
</Grid>
<StackPanel FocusManager.FocusedElement="{Binding ElementName=txtIniFocus}">
<TextBox x:Name="txtIniFocus" Margin="6" Text="{Binding Barcode, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="150" Grid.Row="1" TextChanged="TextBox_TextChanged">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding ReceiptCommand}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</Grid>
And, the ReceiptViewModel.cs:
using ProductionScanner.Cores;
using ProductionScanner.MVVM.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Windows;
using System.Windows.Controls.Primitives;
namespace ProductionScanner.MVVM.ViewModel
{
public class ReceiptViewModel: ObservableObject
{
private string _barcode;
public string Barcode
{
get { return _barcode; }
set { _barcode = value; OnPropertyChanged(); }
}
public RelayCommand ReceiptCommand { get; set; }
public ReceiptViewModel()
{
ReceiptCommand = new RelayCommand(x =>
{
receiptInventory();
});
}
private void receiptInventory()
{
if (Barcode.Length == 12)
{
var inventoryIDFrom = Barcode.Substring(0, 6);
var kgIntFrom = Barcode.Substring(6);
var kgDecimalFrom = kgIntFrom.Substring(0,kgIntFrom.Length-4) + "." + kgIntFrom.Substring(kgIntFrom.Length - 4, 3);
ERPRestService _erpRestService = new ERPRestService();
ReceiptItems receiptItems = new ReceiptItems();
receiptItems.InventoryID = inventoryIDFrom;
receiptItems.Qty = Convert.ToDecimal(kgDecimalFrom);
receiptItems.WarehouseID = "WH001";
receiptItems.LocationID = "L001";
receiptItems.LotSerialNbr = "";
receiptItems.ExpirationDate = DateTime.Now;
try
{
var jsonObj1 = new
{
Description = new
{
value = "Receipt"
},
Hold = new
{
value = false
},
Details = new[]
{
new {
InventoryID = new
{
value = receiptItems.InventoryID
},
Qty = new
{
value = receiptItems.Qty
},
WarehouseID = new
{
value = receiptItems.WarehouseID
},
Location = new
{
value = receiptItems.LocationID
}
}
}
};
string entityAsString = JsonConvert.SerializeObject(jsonObj1);
//string parameters1 = "$expand=Details";
var receipt = _erpRestService.Put("InventoryReceipt", null, entityAsString);
string refRelease = JObject.Parse(receipt)["ReferenceNbr"]["value"].ToString();
var release = new
{
entity = new
{
ReferenceNbr = new
{
value = refRelease
}
}
};
string jsonRelease = JsonConvert.SerializeObject(release);
jsonRelease = _erpRestService.Post("InventoryReceipt", "ReleaseInventoryReceipt", jsonRelease);
MessageBox.Show("Your AR Confirm has completed.", "Confirm", MessageBoxButton.OK, MessageBoxImage.Information);
}
catch (Exception ex)
{
throw (ex);
}
finally
{
_erpRestService.Dispose();
}
}
}
}
}
I tried a simplified version of the markup and code.
The messagebox looked a bit suspicious to me as I was thinking it might take focus. What might happen after that.
Use of return was also a concern as I wondered what else return might do.
There's nowhere else for the focus to go.
If I just press tab then the cursor is still in the textbox.
My experimental markup:
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Background="#0F0F2D"
Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text="Foods"
Foreground="White"
Grid.Column="1"
VerticalAlignment="Center"
HorizontalAlignment="Left"
/>
<TextBlock Text="Records"
Foreground="White"
Grid.Column="2"
VerticalAlignment="Center"
HorizontalAlignment="Center"
/>
</Grid>
<StackPanel FocusManager.FocusedElement="{Binding ElementName=txtIniFocus}">
<TextBox x:Name="txtIniFocus" Margin="6" Text="{Binding Barcode, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" TextWrapping="Wrap" VerticalAlignment="Top" Width="150" Grid.Row="1">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding ReceiptCommand}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</Grid>
</Window>
My viewmodel
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private string barcode = "65765765";
[RelayCommand]
private async Task Receipt()
{
// Your receipt processing would go here
MessageBox.Show("Your AR Confirm has completed.", "Confirm", MessageBoxButton.OK, MessageBoxImage.Information);
Barcode=string.Empty;
}
}
I hit enter, the messagebox shows. I click OK. The messagebox closes, textbox is empty and the cursor is in the textbox.
If what you've shown us was all you have then I think setting Barcode to string.Empty would probably work.
Not sure it'd make much difference but my property changed notification is from the community toolkit mvvm and using the code generator. It will check for equality before raising property changed.
I'm not sure what your observableobject is there.
I still think the messagebox is a bad idea as the user has to pick the mouse up and click. An on screen indicator would be something to consider instead.
FWIW
I would also recommend just checking the length is 12 and drive the processing that way.
If you do both then the user could just scan, the receipt is done, scan the next receipt is done, scan....
They wouldn't have to touch keyboard or mouse.
That's the approach I've used for warehouse and product scanning on what sound like similar apps.

C# UWP create check-list table programmatically

I have task to create in C# UWP user created check-list.
But I have stuck from the beginning cause XAML is new for me, so I have no idea what to start from.
So, I have textbox to enter title, task or subtask to in listbox (priviously added to) selected task.
this is my xaml how it looks like now:
<Page
x:Class="Table1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Table1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<TextBox x:Name="txt" HorizontalAlignment="Left" Height="71" Margin="71,247,0,0" Text="TextBox" VerticalAlignment="Top" Width="395"/>
<RadioButton x:Name="title" Content="Add Title" HorizontalAlignment="Left" Margin="71,86,0,0" VerticalAlignment="Top"/>
<RadioButton x:Name="task" Content="Add Task" HorizontalAlignment="Left" Margin="71,123,0,0" VerticalAlignment="Top"/>
<RadioButton x:Name="subtask" Content="Add Subtask" HorizontalAlignment="Left" Margin="71,155,0,0" VerticalAlignment="Top"/>
<ListBox x:Name="listbox" HorizontalAlignment="Left" Height="68" Margin="71,354,0,0" VerticalAlignment="Top" Width="395"/>
<Button x:Name="btn" Content="Button" HorizontalAlignment="Left" Margin="401,483,0,0" VerticalAlignment="Top" Click="btn_Click"/>
</Grid>
</Page>
There are the code:
public class subtasks
{
public string parent { get; set; }
public string subtask { get; set; }
public subtasks(string parenti, string subtaski)
{
parent = parenti;
subtask = subtaski;
}
public void setsub(string parenti, string sub)
{
parent = parenti;
subtask = sub;
}
}
List<string> Tasks = new List<string>();
List<subtasks> sub = new List<subtasks>();
private void btn_Click(object sender, RoutedEventArgs e)
{
string parent = "";
string Title;
string Task;
string Subtask;
if (title.IsChecked==true)
{
Title = txt.Text;
adding(Title, parent, 1);
}
else if (task.IsChecked==true)
{
Task = txt.Text;
adding(Task, parent, 2);
}
else if (subtask.IsChecked==true)
{
parent = listbox.SelectedItem.ToString();
Subtask = txt.Text;
adding(Subtask, parent, 3);
}
else
{
}
}
private void adding(string str, string par, int x)
{
subtasks subi = new subtasks(par,str);
RowDefinition row = new RowDefinition();
TextBlock text = new TextBlock();
if (x==1)
{
print(str);
}
else if (x==2)
{
Tasks.Add(str);
listbox.Items.Add(str);
text.Text = str;
print(str);
}
else
{
sub.Add(subi);
print(str);
}
}
private void print(string title)
{
int step = 0;
Grid gridwin = new Grid();
gridwin.Children.Clear();
RowDefinition row = new RowDefinition();
TextBlock text = new TextBlock();
text.Text = title;
Grid.SetColumn(text, 0);
Grid.SetRow(text, step);
step++;
for (int i = 0; i < Tasks.Count; i++)
{
text.Text = Tasks[i].ToString();
gridwin.Children.Add(text);
Grid.SetColumn(text, 0);
Grid.SetRow(text, step);
step++;
for (int k = 0; k < sub.Count; k++)
{
if (sub[k].parent == Tasks[i])
{
text.Text = sub[k].subtask.ToString();
gridwin.Children.Add(text);
Grid.SetColumn(text, 0);
Grid.SetRow(text, step);
step++;
}
}
}
}
As you see I need to clear and put data every time the button is clicked, cause you never know when user will decide to add new subtask for previously added task. So, the question is, how to make the table with column1 with tasks and subtasks and column2 which is chekbox.
What you want to probably do is to create a DataTemplate. You use this to specify how list items should be displayed and formatted. This way you can specify you want to lay them out as a Grid with two columns like description and CheckBox. Take a look into the documentation to see some examples of DataTemplates. You can also see the Azure Mobile Apps quickstart for UWP, because although it is focused on demonstrating Microsoft Azure integration to UWP, it is actually a to-do app, which should give you some inspiration for building your own.
The layout could look like this:
<ListBox x:Name="listbox" HorizontalAlignment="Left" Height="68" Margin="71,354,0,0" VerticalAlignment="Top" Width="395">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Text}" />
<CheckBox Grid.Column="1" IsChecked="{Binding IsChecked, Mode=TwoWay}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can see my code is also using {Binding} syntax, which you will also need to learn a bit about to be able to know when the user has checked a to-do item in the list. I suggest you to take a look at a simple tutorial sample like here. In fact, data-binding is one of the most important things when building XAML-based apps and when you get to understand this concept, it will help you a lot on the way to becoming a UWP ninja :-) .
Why dont use the UWP DataGrid with CheckBox?
XAML
<toolkit:DataGrid Grid.Column="0" ItemsSource="{x:Bind myItemsToBind}"
x:Name="dgwDeviceSPNs" MinWidth="100"
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible"
AlternatingRowBackground="Transparent"
AreRowDetailsFrozen="False"
AreRowGroupHeadersFrozen="True"
AutoGenerateColumns="False"
CanUserSortColumns="False"
CanUserReorderColumns="True"
RowGroupHeaderPropertyNameAlternative=""
CanUserResizeColumns="True"
MaxColumnWidth="200"
FrozenColumnCount="0"
GridLinesVisibility="Horizontal"
HeadersVisibility="None"
IsReadOnly="True"
RowDetailsVisibilityMode="Collapsed"
SelectionMode="Single">
<toolkit:DataGrid.Columns>
<toolkit:DataGridTemplateColumn MinWidth="10">
<toolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Padding="2">
<CheckBox ToolTipService.ToolTip="{Binding Name}" IsChecked="{Binding IsSelected, Mode=TwoWay}" Content="{Binding Name}"></CheckBox>
</StackPanel>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>
</toolkit:DataGrid.Columns>
</toolkit:DataGrid>

UWP Object reference not set to an instance of an object when adding item to Azure easy table

I have a popup window that takes in input from a user and then should send it to a model which then POSTS it to an azure easy table. When I build the project everything runs fine until I hit the submit button then the app crashes and I get the Null Exception Object reference not set to an instance of an object.
XAML for input:
<Popup x:Name="ppup" IsOpen="False" IsLightDismissEnabled="True"
Width="320" HorizontalAlignment="Left">
<Popup.ChildTransitions>
<TransitionCollection>
<!--<EdgeUIThemeTransition Edge="Left" />-->
<PaneThemeTransition Edge="Left" />
</TransitionCollection>
</Popup.ChildTransitions>
<Grid Width="380" Height="{Binding ElementName=flyoutPane, Path=Height}" Background="{ThemeResource FlyoutBackgroundThemeBrush}" >
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="10,10,10,10" >
<TextBlock Name="NameText" Text="Enter Name:"/>
<TextBox Name="NameBox" Width="200" Height="50"/>
<TextBlock Name="SetsText" Text="Enter Sets:"/>
<TextBox Name="SetsBox" Width="200" Height="50"/>
<TextBlock Name="TimeText" Text="Enter Time to complete:"/>
<TextBox Name="TimeBox" Width="200" Height="50"/>
<Button Name="SubmitBtn" Height="30" Width="100" Content="Submit" Click="SubmitBtn_Click"/>
</StackPanel>
</Grid>
</Popup>
C# for handling input and passing it to model:
CombatTableView ctv = new CombatTableView();
private async void SubmitBtn_Click(object sender, RoutedEventArgs e)
{
DrillItem drillItem = new DrillItem();
String Name = NameBox.Text;
int Sets = Int32.Parse(SetsBox.Text);
int Time = Int32.Parse(TimeBox.Text);
await ctv.combatDrillsTable.AddDrill(drillItem, Name, Sets, Time, parameters);
ppup.IsOpen = false;
var dialog = new MessageDialog("Your message here");
await dialog.ShowAsync();
}
View Model:
class CombatTableView
{
public CombatDrillsTable combatDrillsTable { get; set; }
public CombatTableView()
{
this.combatDrillsTable = new CombatDrillsTable();
}
}
Model for interacting with database:
public async Task AddDrill(DrillItem drillItem, String n, int s, int t, string sty)
{
drillItem.Name = n;
drillItem.Sets = s;
drillItem.SetTime = t;
drillItem.Style = sty;
await App.MobileService.GetTable<DrillItem>().InsertAsync(drillItem);
drills.Add(drillItem);
}
In my case the problem was due to a checkbox accidentally bound to the event instead of the property:
<CheckBox x:Name="chkIsActive" Checked="{Binding IsActive}" />
instead of
<CheckBox x:Name="chkIsActive" IsChecked="{Binding IsActive}" />
There was a null value inside combatDrillsTable and the list that was to hold the objects null too because i hadn't put anything into my easy table at that stage so it was throwing a null exception.

WPF NavigationService is null

I'm learning WPF (moving from Procedural PHP) and have written the following to navigate from 'MainWindow' to 'Page1', where there are no errors with the login credentials, but the local variable 'nav' is always null (hence displaying an error message):
namespace YM_POS_20160229_0949
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void ClickLoginSubmitButton(object sender, RoutedEventArgs e)
{
// Dictionary object is c# equivalent of PHP's 'array["key"] = "value"'
Dictionary<string, string> errMsg = new Dictionary<string, string>();
// declare variables
string varUserName;
string varUserPass;
// define the variables whilst trimming the values passed
varUserName = LoginUsername.Text.Trim();
varUserPass = LoginPassword.Password.Trim();
// ensure something has been submitted & perform validation on the values submitted
// if there are no errors, navigate to the users dashboard (aka Page1)
NavigationService nav = NavigationService.GetNavigationService(new Page1());
// check if the nav variable is populated
if (nav != null)
{
nav.Navigate(nav);
}
else
{
// display an error message to the user advising them an error has occurred and Page1 is not available
MessageBox.Show("An error has occured. unable to proceed to " + nav);
}
}
}
}
Any help greatly appreciated.
Thanks
Newbie Matt
//UI / XAML
<Window x:Class="YM_POS_20160229_0949.MainWindow"
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"
xmlns:local="clr-namespace:YM_POS_20160229_0949"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="123*"/>
<ColumnDefinition Width="394*"/>
</Grid.ColumnDefinitions>
<TextBox x:Name="LoginUsername" HorizontalAlignment="Left" Height="23" Margin="56.649,55,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="120" Grid.Column="1"/>
<PasswordBox x:Name="LoginPassword" HorizontalAlignment="Left" Height="23" Margin="56.649,100,0,0" Password="Password" VerticalAlignment="Top" Width="120" Grid.Column="1" />
<Button x:Name="LoginSubmitButton" Content="Submit" HorizontalAlignment="Left" Margin="81.649,172,0,0" VerticalAlignment="Top" Width="75" Click="ClickLoginSubmitButton" Grid.Column="1"/>
</Grid>
</DockPanel>
</Window>

C# User Must Add Multiple Buttons to WPF and Buttons Must Persist

I am attempting to create a program in which the User can create multiple profiles. These profiles can be accessed via buttons that appear as each profile is completed.
My problem:
I have no clue how to make the created buttons persist after the program is exited(I need to save the buttons?)
Visually, this is program's process: 1) Enter your information, click continue 2) View a display page of what you entered, click done. 3) This adds a button to the final window, the button of course takes you to 4) Your profile you just created.
After this, the program ends and nothing is saved. I'm fairly new to c# and am quite confused on how to "save" multiple buttons without massively complicating the code. I'm a complete noob to c# and have a little Java experience. Am I going about this correctly? I'm pretty sure its possible but have no idea to go about it.
I will include my code below. I'm working in visual studios 2012. any help would be appreciated!
MainWindow XAML:
<Window x:Class="VendorMain.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Label Content="FirstName" HorizontalAlignment="Left" Margin="63,45,0,0" VerticalAlignment="Top"/>
<Label Content="LastName" HorizontalAlignment="Left" Margin="63,71,0,0" VerticalAlignment="Top"/>
<Label Content="Image" HorizontalAlignment="Left" Margin="63,102,0,0" VerticalAlignment="Top"/>
<Image Name="imgPhoto" Stretch="Fill" Margin="63,133,303,69"></Image>
<Button Name="UploadImageButton" Content="Upload Image" HorizontalAlignment="Left" Margin="130,105,0,0" VerticalAlignment="Top" Width="84" Click="UploadImageButton_Click"/>
<TextBox Name="AssignFirstName" Text="{Binding SettingFirstname}" HorizontalAlignment="Left" Height="23" Margin="130,48,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" />
<TextBox Name="AssignLastName" Text="{Binding SettingLastName}" HorizontalAlignment="Left" Height="23" Margin="130,75,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button Name="ContinueToDisplayWindow" Content="Continue" HorizontalAlignment="Left" Margin="409,288,0,0" VerticalAlignment="Top" Width="75" Click="ContinueToDisplayWindow_Click" />
</Grid>
MainWindow Code:
namespace VendorMain
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void UploadImageButton_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog op = new OpenFileDialog();
op.Title = "Select a picture";
op.Filter = "All supported graphics|*.jpg;*.jpeg;*.png|" +
"JPEG (*.jpg;*.jpeg)|*.jpg;*.jpeg|" +
"Portable Network Graphic (*.png)|*.png";
if (op.ShowDialog() == true)
{
imgPhoto.Source = new BitmapImage(new System.Uri(op.FileName));
//SettingImage.Source = imgPhoto.Source;
}
}
private void ContinueToDisplayWindow_Click(object sender, RoutedEventArgs e)
{
DisplayPage displaypg = new DisplayPage();
displaypg.DpFirstName.Content = AssignFirstName.Text;
displaypg.DpLastName.Content = AssignLastName.Text;
displaypg.DpImage.Source = imgPhoto.Source;
displaypg.Show();
}
}
}
DisplayPage XAML:
<Window x:Class="VendorMain.DisplayPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DisplayPage" Height="300" Width="525">
<Grid>
<Label Name="DpFirstName" Content="{Binding getFirstNamePermenent}" HorizontalAlignment="Left" Margin="86,55,0,0" VerticalAlignment="Top"/>
<Label Name="DpLastName" Content="{Binding getLastNamePermenent}" HorizontalAlignment="Left" Margin="87,80,0,0" VerticalAlignment="Top"/>
<Image Name="DpImage" HorizontalAlignment="Left" Height="100" Margin="94,111,0,0" VerticalAlignment="Top" Width="100"/>
<Button Name="ButtonizeThisProfile_Button" Content="Done" HorizontalAlignment="Left" Margin="420,238,0,0" VerticalAlignment="Top" Width="75" Click="ButtonizeThisProfile_Button_Click"/>
</Grid>
DisplayPage Code:
namespace VendorMain
{
/// <summary>
/// Interaction logic for DisplayPage.xaml
/// </summary>
public partial class DisplayPage : Window
{
public Button bot1;
public DisplayPage()
{
InitializeComponent();
}
private void newBtn_Click(object sender, RoutedEventArgs e)
{
carryToFinalView();
}
private void ButtonizeThisProfile_Button_Click(object sender, RoutedEventArgs e)
{
UserProfiles uPro = new UserProfiles();
System.Windows.Controls.Button newBtn = new Button();
newBtn.Content = "Person1";
newBtn.Name = "NewProfileButtonAccess";
newBtn.Click += new RoutedEventHandler(newBtn_Click);
uPro.ButtonArea.Children.Add(newBtn);
uPro.Show();
}
public void carryToFinalView()
{
DisplayPage displaypg = new DisplayPage();
displaypg.DpFirstName.Content = DpFirstName.Content;
displaypg.DpLastName.Content = DpLastName.Content;
displaypg.DpImage.Source = DpImage.Source;
displaypg.Show();
}
}
}
UserProfile XAML:
<Window x:Class="VendorMain.UserProfiles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="UserProfiles" Height="300" Width="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".8*" />
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="6*"/>
<RowDefinition Height="11*"/>
</Grid.RowDefinitions>
<Label Content="User Profiles: " HorizontalAlignment="Left" Margin="37,47,0,0" VerticalAlignment="Top"/>
<StackPanel Name="ButtonArea" Grid.Column="2" Grid.Row="2">
</StackPanel>
<Button Name="AddAnotherProfileButton" Content="Button" HorizontalAlignment="Left" Margin="35,146,0,0" Grid.Row="1" VerticalAlignment="Top" Width="75" Click="AddAnotherProfileButton_Click"/>
</Grid>
UserProfile Code:
namespace VendorMain
{
public partial class UserProfiles : Window
{
public UserProfiles()
{
InitializeComponent();
}
private void AddAnotherProfileButton_Click(object sender, RoutedEventArgs e)
{
MainWindow mw = new MainWindow();
mw.Show();
}
}
}
As a self proclaimed 'noob', I fear that you won't receive an answer here. I certainly don't have time to repeatedly come back to answer a whole continuing stream of related questions. I also don't have time to provide you with a complete solution. However, I am happy to provide you with sort of 'pseudo code' to at least point you in the right direction... you will have to do a lot of this yourself.
So first things first, as mentioned in a comment, although it is possible, we don't generally save the UI Button objects, but instead we save the data that relates to the user profiles. Therefore, if you haven't done this already, create a User class that has all of the relevant properties. Implement the INotifyPropertyChanged Interface in it and add the SerializableAttribute to the class definition... this will enable you to save this class type as binary data.
Next, in your UI, don't add each Button in xaml... there's a better way. One way or another, add a collection property of type User or whatever your class is called, and set this as the ItemsSource of a ListBox. The idea here is to add a DataTemplate for your User type which will display each of the User items in the collection as a Button:
<DataTemplate x:Key="UserButtonTemplate" DataType="{x:Type DataTypes:User}">
<Button Text="{Binding Name}" Width="75" Click="AddAnotherProfileButton_Click" />
</DataTemplate>
You can find out more about DataTemplates in the Data Templates article.
Implementing this collection allows you to have and display any number of user profiles in your UI, rather than being restricted by screen size as your original example would be.
Now finally, on to saving the data... this can be achieved relatively simply using the following code:
try
{
using (Stream stream = File.Open("ProfileData.bin", FileMode.Create))
{
BinaryFormatter binaryFormatter = new BinaryFormatter();
binaryFormatter .Serialize(stream, usersList);
}
}
catch { }
One thing to note is that WPF wants us to use the ObservableCollection<T> class when displaying data in the UI, but this class causes problems when serializing data with this method... therefore, you will need to convert your ObservableCollection<T> to a List<T> or similar. However, this can be easily achieved:
List<User> usersList = users.ToList();
You can find out how to de-serialize your data from the C# Serialize List tutorial. You would deserialize (or load the data from the saved file) each time your application starts and re-save the file each time the program closes. You can add an event handler to the Application.Deactivated Event or the Window.Closing which gets called when the application closes, so you can put your code to save the file in there.
Well, I took longer and wrote more than I had expected, so I hope that helps.

Categories

Resources