I've looked through multiple solutions on here and the internet on how to solve this but I can't seem to get it. I'm just trying to make a simple login for an application I'm developing. Eventually I'll have it connected to an SQL database on a server but forget that right now. Here's the code:
<Controls:MetroWindow x:Class="ScotiaPlayTrade.Wpf.Application.LoginWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ff="clr-namespace:ScotiaPlayTrade.Wpf.Application"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:System="clr-namespace:System;assembly=mscorlib" Title="Authentication"
Height="400" Width="600" WindowStartupLocation="CenterScreen" TitleForeground="#999988"
ResizeMode="NoResize" WindowStyle="None" WindowState="Normal" ShowMaxRestoreButton="False">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--Username Layout-->
<TextBlock
Margin="10,10,10,10"
Grid.Column="0"
Grid.Row="0">
User Name
</TextBlock>
<TextBox
Margin="10,10,10,10"
x:Name="userName"
Grid.Column="5"
Grid.Row="0"
Text="{x:Static System:Environment.UserName}"
IsReadOnly="True">
</TextBox>
<!--Password Layout-->
<TextBlock
Margin="10,10,10,10"
Grid.Column="0"
Grid.Row="1">
Password
</TextBlock>
<PasswordBox
Margin="10,10,10,10"
Width="200"
x:Name="PasswordBox"
ff:PasswordBoxAssistant.BindPassword="true" x:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Column="1"
Grid.Row="1">
</PasswordBox >
<!--Buttons Layout-->
<StackPanel Margin="3,3,3,3" Orientation="Horizontal" Grid.Column="1" Grid.Row="2">
<Button
Margin="10,10,10,10"
Click="Login_Click"
IsDefault="True">
Login
</Button>
<Button
Margin="10,10,10,10"
Click="Exit_Click"
IsCancel="True">
Exit
</Button>
<Button
Margin="10,10,10,10"
Click="AddNewUser_Click"
IsCancel="True">
New User
</Button>
</StackPanel>
</Grid>
That's my LoginWindow.xaml and here's my cs code for the window.
public partial class LoginWindow
{
public LoginWindow()
{
InitializeComponent();
}
//Clicking Login Button
private void Login_Click(object sender, RoutedEventArgs e)
{
//Check that password field is not null
if (PasswordBox != null)
{
//Check that username matches password, if it matches then open main window
//Launch the main window after authentication is complete
MainWindow myMainWindow = new MainWindow();
myMainWindow.Show();
//Close the login screen
Close();
}
else
{
MessageBox.Show("Password field cannot be empty!");
}
}
//Clicking Exit Button
private void Exit_Click(object sender, RoutedEventArgs e)
{
Close();
}
//Clicking Exit Button
private void AddNewUser_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Not yet implemented");
}
}
I've tried everything with passwordbox it keeps giving me an error that WPF doesn't support it, things like PasswordBoxAssistant, and Helper. Would appreciate any help. Here are the error messages:
Error 1 PasswordBoxAssistant is not supported in a Windows Presentation Foundation (WPF) project.
Error 5 The property 'PasswordBoxAssistant.BindPassword' does not exist in XML namespace 'http://schemas.microsoft.com/winfx/2006/xaml'. Line 50 Position 13.
Ok so now I made a class called PasswordValidation and added the PasswordBoxAssistant code.
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.Shapes;
namespace ScotiaPlayTrade.Wpf.Application
{
public static class PasswordBoxAssistant
{
public static readonly DependencyProperty BoundPassword =
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
"BindPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
private static readonly DependencyProperty UpdatingPassword =
DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));
private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBox box = d as PasswordBox;
// only handle this event when the property is attached to a PasswordBox
// and when the BindPassword attached property has been set to true
if (d == null || !GetBindPassword(d))
{
return;
}
// avoid recursive updating by ignoring the box's changed event
box.PasswordChanged -= HandlePasswordChanged;
string newPassword = (string)e.NewValue;
if (!GetUpdatingPassword(box))
{
box.Password = newPassword;
}
box.PasswordChanged += HandlePasswordChanged;
}
private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
// when the BindPassword attached property is set on a PasswordBox,
// start listening to its PasswordChanged event
PasswordBox box = dp as PasswordBox;
if (box == null)
{
return;
}
bool wasBound = (bool)(e.OldValue);
bool needToBind = (bool)(e.NewValue);
if (wasBound)
{
box.PasswordChanged -= HandlePasswordChanged;
}
if (needToBind)
{
box.PasswordChanged += HandlePasswordChanged;
}
}
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox box = sender as PasswordBox;
// set a flag to indicate that we're updating the password
SetUpdatingPassword(box, true);
// push the new password into the BoundPassword property
SetBoundPassword(box, box.Password);
SetUpdatingPassword(box, false);
}
public static void SetBindPassword(DependencyObject dp, bool value)
{
dp.SetValue(BindPassword, value);
}
public static bool GetBindPassword(DependencyObject dp)
{
return (bool)dp.GetValue(BindPassword);
}
public static string GetBoundPassword(DependencyObject dp)
{
return (string)dp.GetValue(BoundPassword);
}
public static void SetBoundPassword(DependencyObject dp, string value)
{
dp.SetValue(BoundPassword, value);
}
private static bool GetUpdatingPassword(DependencyObject dp)
{
return (bool)dp.GetValue(UpdatingPassword);
}
private static void SetUpdatingPassword(DependencyObject dp, bool value)
{
dp.SetValue(UpdatingPassword, value);
}
}
}
The following are the errors I get:
Error 1 The name "PasswordBoxAssistant" does not exist in the namespace "clr-namespace:ScotiaPlayTrade.Wpf.Application". 50 13
Error 2 PasswordBoxAssistant is not supported in a Windows Presentation Foundation (WPF) project. 50 58
Error 3 The attachable property 'BindPassword' was not found in type 'PasswordBoxAssistant'. 50 13
Related
So I have a simple Starting Window, where buttons like: "Login", "Register", "Exit" and finally "Start Program" are.
The "Start Program"-button is by default invisible.
The "Login"-button doesn't work yet so forget about it.
The "Exit"-button closes the program.
The "Register"-button opens an new Window, where you can type in your username and password. This is then saved in a table connected with a SQL-Database.
I have a public bool that is called "LogIn" where as default is set to false. When I successfully register I set it to true. In my Startup.xaml I then check if the bool "LogIn" is true, if it is true it should set the visibility of my "Start Program"-button to visible. But unfortunately it doesn't work.
Thanks in advance for your help.
My Code:
My Startup.xaml:
<Window x:Class="MiiUse.Startup"
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:MiiUse"
mc:Ignorable="d"
Title="Welcome To MiiUse" Height="500" Width="850"
Style="{StaticResource Startup}"
StateChanged="MaximizeWindow" ResizeMode="NoResize">
<Grid>
<Button Style="{StaticResource RoundButton}" Content="Start Program" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Start" x:Name="StartButton" Visibility="Hidden"/>
<Button Style="{StaticResource RoundButton}" Content="Exit" HorizontalAlignment="Right" VerticalAlignment="Bottom" Click="Button_Exit" />
<Button Style="{StaticResource RoundButton}" Content="Register" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,0,16,0" Click="Button_Register"/>
<Button Style="{StaticResource RoundButton}" Content="Login" HorizontalAlignment="Right" Margin="0,0,77,0" VerticalAlignment="Top" RenderTransformOrigin="0.379,0.002" Click="Button_Login"/>
</Grid>
</Window>
How it looks like:
My Startup.xaml.cs:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
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.Shapes;
namespace MiiUse
{
/// <summary>
/// Interaction logic for Startup.xaml
/// </summary>
public partial class Startup : Window
{
public Startup()
{
InitializeComponent();
Registration registration = new Registration();
if (registration.LogIn == true)
{
StartButton.Visibility = Visibility.Visible;
}
}
private void Button_Start(object sender, RoutedEventArgs e)
{
MainWindow mainWindow = new MainWindow();
this.Close();
mainWindow.Show();
}
private void Button_Exit(object sender, RoutedEventArgs e)
{
this.Close();
}
private void MaximizeWindow(object sender, EventArgs e)
{
if (this.WindowState == WindowState.Maximized)
{
this.WindowState = WindowState.Normal;
}
}
private void Button_Register(object sender, RoutedEventArgs e)
{
Registration registration = new Registration();
registration.Show();
}
private void Button_Login(object sender, RoutedEventArgs e)
{
}
}
}
My Registration.xaml:
<Window x:Class="MiiUse.Registration"
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:MiiUse"
mc:Ignorable="d"
Title="Registration" Height="320" Width="370">
<Grid>
<Label Content="Enter your Username:" HorizontalAlignment="Left" Margin="44,44,0,0" VerticalAlignment="Top"/>
<Label Content="Enter your Password:" HorizontalAlignment="Left" Margin="44,98,0,0" VerticalAlignment="Top" />
<Button Content="Submit" HorizontalAlignment="Left" Margin="44,245,0,0" VerticalAlignment="Top" Click="Submit"/>
<Button Content="Cancel" HorizontalAlignment="Left" Margin="124,245,0,0" VerticalAlignment="Top" Click="Cancel"/>
<TextBox x:Name="Username" HorizontalAlignment="Left" Margin="44,75,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<PasswordBox x:Name="Password" HorizontalAlignment="Left" Margin="44,129,0,0" VerticalAlignment="Top" Width="120"/>
</Grid>
</Window>
How it looks like:
My Registration.xaml.cs:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
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.Shapes;
namespace MiiUse
{
/// <summary>
/// Interaction logic for Registration.xaml
/// </summary>
public partial class Registration : Window
{
public Registration()
{
InitializeComponent();
}
public bool LogIn = false;
private void Submit(object sender, RoutedEventArgs e)
{
string username = Username.Text;
string password = Password.Password;
if(Password.Password.Length == 0)
{
MessageBox.Show("Password can't be empty!", "Invalid Input!", MessageBoxButton.OK, MessageBoxImage.Error);
Password.Focus();
}else if(Username.Text.Length == 0)
{
MessageBox.Show("Username can't be empty!", "Invalid Input!", MessageBoxButton.OK, MessageBoxImage.Error);
Username.Focus();
}
else
{
using (SqlConnection connection = new SqlConnection(Properties.Settings.Default.connection_String))
{
using SqlCommand sqlCommandGetTemplatesAndDrafts = new SqlCommand(#$"
Insert into tbl_Users (Username, Password) values('{username}','{password}')", connection);
connection.Open();
sqlCommandGetTemplatesAndDrafts.ExecuteNonQuery();
connection.Close();
}
MessageBox.Show("You were successfully registered, and automatically logged in!", "Success", MessageBoxButton.OK, MessageBoxImage.Information);
Close();
LogIn = true;
}
}
private void Cancel(object sender, RoutedEventArgs e)
{
Close();
}
}
}
You are not setting the Visibility property after the Registration window has been opened.
You could display the Registration window as a modal:
private void Button_Register(object sender, RoutedEventArgs e)
{
Registration registration = new Registration();
registration.ShowDialog();
if (registration.LogIn == true)
{
StartButton.Visibility = registration.LogIn ? Visibility.Visible : Visibility.Hidden;
}
}
Also set LogIn before you close the window in Submit:
...
LogIn = true;
Close();
Another option would be to inject Registration with a reference to MainWindow:
private readonly MainWindow _mainWindow;
public Registration(MainWindow mainWindow)
{
_mainWindow = mainWindow;
InitializeComponent();
}
...
private void Submit(object sender, RoutedEventArgs e)
{
...
_mainWindow.StartButton.Visibility = Visibility.Visible;
Close();
...
MainWindow:
private void Button_Register(object sender, RoutedEventArgs e)
{
Registration registration = new Registration(this);
registration.Show();
}
Buf if you are serious about WPF and XAML, you should learn [MVVM].
convert your "LogIn" from bool to "Visibility" so instead of true or false we can mention Visibility.visible or Visibility.hidden. as follows:
public Visibility LogIn = Visibility.Hidden;
finally, bind your startup button visibility to this LogIn variable
So on successful completion of SQL :
LogIn = Visibility.visible ;
finally binding:
<Button Style="{StaticResource RoundButton}" Content="Start Program" HorizontalAlignment="Center" VerticalAlignment="Center" Click="Button_Start" x:Name="StartButton" Visibility="{binding LogIn}"/>
but this LogIn should either be in code behind or View model
but I think the best way to do it is to create a public class called helper and store these connection variables in it so that they are accessed throughout your application
create propoerty :
private Visibility _logIn;
public Visibility LogIn
{
get => _logIn;
set
{
_logIn= value;
OnPropertyChanged();
}
}
and some wherer in your application initialise it to hidden
I'm new to WPF following an attempt to move from winforms so this is basic question however i'm trying to add to a string from a button click. The scenario is basically a keypad full of buttons (0 - 9) and the user presses these as to enter a code as a type of PIN. The method of going about this is non-negotiable so i cannot just replace with a text box and have the user type this. I have a little knowledge on bindings however it appears to be the appending to a string which is throwing me out as, obviously, all the buttons (0-9) need to be able to append to this string in sequence. So anyway, i have a ViewModel with a property called 'EnteredCode' and the buttons reside in a grid named 'buttonsGrid'. Would i be correct in thinking i handle the ButtonBase.Click event at the Grid level, determine which one was clicked and then append to the string? The appending to the string is obviously the problem here which i need help with but just as general feedback to best practise!
Code examples would also be a huge help.
TIA
So, you can treat WPF just as windows forms and solve this in the codebehind MainWindow.xaml.cs
Example:
DemonstrationViewModel demoViewModel;
public MainWindow()
{
InitializeComponent();
demoViewModel = new DemonstrationViewModel();
DataContext = demoViewModel;
}
private void alsoDemoButton_Click(object sender, RoutedEventArgs e)
{
demoViewModel.EnteredCode += "Clicked";
}
However, with the mention of ViewModel in your statement, you are likely following a MVVM pattern and writing in the code behind is not recommended.
If you are following a MVVM pattern, ICommands would be one way to go.
Pseudocode-ish example
XAML
<Button x:Name="demoButton" Command="{Binding InsertCommand}"/>
ViewModel
#region Constructor
public DemonstrationViewModel()
{
InsertCommand = new RelayCommand(ExecuteInsert, CanExecuteInsert);
}
#endregion
private void ExecuteInsert()
{
EnteredCode += "Clicked! ";
}
Further reading on ICommand in MVVM
You must be trying to bind Password property of PasswordBox to your ViewModel property. Password property is not bindable as it is not a DependencyProperty. This is for security reasons.
However if you want to make it bindable, you have to use a custom AttachedProperty. Now, you are trying to input PIN by pressing buttons like in ATM machines, and want your password bindable too. See a sample below to get you started.
xaml code :
<Window x:Class="WpfEvents._32802407.Win32802407"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pwd="clr-namespace:PasswordExtras"
Title="Win32802407" Height="354.136" Width="385.714">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="143*"/>
<ColumnDefinition Width="46*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="16*"/>
<RowDefinition Height="19*"/>
<RowDefinition Height="32*"/>
<RowDefinition Height="95*"/>
</Grid.RowDefinitions>
<TextBlock TextWrapping="Wrap" Text="Welcome Joshua !" FontSize="18" VerticalAlignment="Center" Margin="10,4,0,4"/>
<PasswordBox x:Name="pbPin" pwd:PasswordBoxAssistant.BindPassword="True" pwd:PasswordBoxAssistant.BoundPassword="{Binding Path=PIN, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Center" Grid.Row="2" VerticalAlignment="Center" Width="120" FontSize="18" BorderThickness="0"/>
<StackPanel Grid.Column="1" HorizontalAlignment="Left" Height="170" Margin="10,10,0,0" Grid.Row="3" VerticalAlignment="Top" Width="72">
<Button Content="Done" Margin="0,15,0,0" Height="31"/>
<Button Content="Clear" Margin="0,15,0,0" Height="31"/>
<Button Content="Cancel" Margin="0,15,0,0" Height="31"/>
</StackPanel>
<WrapPanel ButtonBase.Click="NumericButtons_Click" HorizontalAlignment="Left" Height="147" Margin="10,23,0,0" Grid.Row="3" VerticalAlignment="Top" Width="266">
<Button Content="1" Width="75" Margin="5" Height="25"/>
<Button Content="2" Width="75" Margin="5" Height="25"/>
<Button Content="3" Width="75" Margin="5" Height="25"/>
<Button Content="4" Width="75" Margin="5" Height="25"/>
<Button Content="5" Width="75" Margin="5" Height="25"/>
<Button Content="6" Width="75" Margin="5" Height="25"/>
<Button Content="7" Width="75" Margin="5" Height="25"/>
<Button Content="8" Width="75" Margin="5" Height="25"/>
<Button Content="9" Width="75" Margin="5" Height="25"/>
<Button Content="0" Width="75" Margin="5" Height="25"/>
</WrapPanel>
<TextBlock HorizontalAlignment="Left" Margin="23,9,0,0" Grid.Row="1" TextWrapping="Wrap" Text="Enter your pin or press cancel" VerticalAlignment="Top"/>
</Grid>
</Window>
xaml code-behind :
using System;
using System.Windows;
using System.Windows.Controls;
using System.Diagnostics;
namespace WpfEvents._32802407
{
/// <summary>
/// Interaction logic for Win32802407.xaml
/// </summary>
public partial class Win32802407 : Window
{
ViewModelATM atm = new ViewModelATM();
public Win32802407()
{
InitializeComponent();
this.DataContext = atm;
}
private void NumericButtons_Click(object sender, RoutedEventArgs e)
{
string pwd = PasswordExtras.PasswordBoxAssistant.GetBoundPassword(pbPin);
if (pwd.Length == 4)
{
e.Handled = true;
return;
}
pwd = pwd + ((Button)e.OriginalSource).Content;
PasswordExtras.PasswordBoxAssistant.SetBoundPassword(pbPin, pwd);
Debug.WriteLine(pwd + " : " + atm.PIN);
}
}
}
namespace PasswordExtras
{
public static class PasswordBoxAssistant
{
public static readonly DependencyProperty BoundPassword =
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
public static readonly DependencyProperty BindPassword = DependencyProperty.RegisterAttached(
"BindPassword", typeof (bool), typeof (PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
private static readonly DependencyProperty UpdatingPassword =
DependencyProperty.RegisterAttached("UpdatingPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));
private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
PasswordBox box = d as PasswordBox;
// only handle this event when the property is attached to a PasswordBox
// and when the BindPassword attached property has been set to true
if (d == null || !GetBindPassword(d))
{
return;
}
// avoid recursive updating by ignoring the box's changed event
box.PasswordChanged -= HandlePasswordChanged;
string newPassword = (string)e.NewValue;
if (!GetUpdatingPassword(box))
{
box.Password = newPassword;
}
box.PasswordChanged += HandlePasswordChanged;
}
private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
// when the BindPassword attached property is set on a PasswordBox,
// start listening to its PasswordChanged event
PasswordBox box = dp as PasswordBox;
if (box == null)
{
return;
}
bool wasBound = (bool)(e.OldValue);
bool needToBind = (bool)(e.NewValue);
if (wasBound)
{
box.PasswordChanged -= HandlePasswordChanged;
}
if (needToBind)
{
box.PasswordChanged += HandlePasswordChanged;
}
}
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox box = sender as PasswordBox;
// set a flag to indicate that we're updating the password
SetUpdatingPassword(box, true);
// push the new password into the BoundPassword property
SetBoundPassword(box, box.Password);
SetUpdatingPassword(box, false);
}
public static void SetBindPassword(DependencyObject dp, bool value)
{
dp.SetValue(BindPassword, value);
}
public static bool GetBindPassword(DependencyObject dp)
{
return (bool)dp.GetValue(BindPassword);
}
public static string GetBoundPassword(DependencyObject dp)
{
return (string)dp.GetValue(BoundPassword);
}
public static void SetBoundPassword(DependencyObject dp, string value)
{
dp.SetValue(BoundPassword, value);
}
private static bool GetUpdatingPassword(DependencyObject dp)
{
return (bool)dp.GetValue(UpdatingPassword);
}
private static void SetUpdatingPassword(DependencyObject dp, bool value)
{
dp.SetValue(UpdatingPassword, value);
}
}
}
ViewModel
using System;
namespace WpfEvents._32802407
{
public class ViewModelATM
{
string _pin = "";
public string PIN { get { return _pin; } set { _pin = value; } }
}
}
I want to implement feature in my WPF application like if someone has log in and he is filling a registration form,but after sometime the account is automatically logout(already implemented this feature),then when the user sign in again, then how to display him the application in the same old state i.e the half filled form or anything he was doing previously with his account,i am looking on net but unable to find any help on this.
There is no quick easy way to do this... However, I would do it like this.
Use the MVVM pattern. As the user enters info into the View, your ViewModel will get the data. When the user logs out, your application should serialize your ViewModel to your favorite format. Mine is JSON. Using JSON.NET, you can serialize the viewmodel out to file.
On startup, you would deserialize the file and restore your viewmodel. Voila, your view should be right back to where it was when they closed the app.
I have made it-
MainWindow.xaml
<Window x:Class="SerializeDeSerialize.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Nikita="clr-namespace:SerializeDeSerialize"
Title="MainWindow" Height="350" Width="525" Closed="Window_Closed_1" Loaded="Window_Loaded_1">
<Window.DataContext>
<Nikita:Movie></Nikita:Movie>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Name="lblTitle" Content="Title:" Grid.Row="0" Grid.Column="0" Margin="10,25,63,10" HorizontalAlignment="Left" Width="164"></Label>
<TextBox Grid.Row="0" Name="txtTitle" Grid.Column="1" Margin="10,25,63,10" Text="{Binding Title}"></TextBox>
<Label Grid.Row="1" Name="lblRating" Content="Rating:" Grid.Column="0" Margin="10,25,63,10" HorizontalAlignment="Left" Width="164"></Label>
<TextBox Grid.Row="1" Name="txtRating" Grid.Column="1" Margin="10,25,63,10" Text="{Binding Rating}"></TextBox>
<Label Grid.Row="2" Name="lblReleaseDate" Content="Release Date:" Grid.Column="0" Margin="10,25,63,10" HorizontalAlignment="Left" Width="164"></Label>
<TextBox Grid.Row="2" Name="txtReleaseDate" Grid.Column="1" Margin="10,25,63,10" Text="{Binding ReleaseDate}"></TextBox>
<Button Grid.Row="3" Content="Window1" Margin="66,36,69,10" Click="Button_Click_1"></Button>
<Button Grid.Row="4" Content="Window2" Margin="66,36,69,10" Click="Button_Click_2"></Button>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.IO;
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.Serialization;
namespace SerializeDeSerialize
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
SerializeDeSerialize.Movie mv = new Movie();
static Movie mm = new Movie();
public MainWindow()
{
InitializeComponent();
DataContext = mv;
}
private void Window_Closed_1(object sender, EventArgs e)
{
SerializeToXML(mv);
}
static public void SerializeToXML(Movie movie)
{
XmlSerializer serializer = new XmlSerializer(typeof(Movie));
TextWriter textWriter = new StreamWriter(#"C:\Users\398780\Desktop\Nikita\movie.xml");
serializer.Serialize(textWriter, movie);
textWriter.Close();
}
private void Window_Loaded_1(object sender, RoutedEventArgs e)
{
mm=DeserializeFromXML();
txtTitle.Text = mm.Title;
txtRating.Text =Convert.ToString(mm.Rating);
txtReleaseDate.Text = Convert.ToString(mm.ReleaseDate);
}
static Movie DeserializeFromXML()
{
XmlSerializer deserializer = new XmlSerializer(typeof(Movie));
TextReader textReader = new StreamReader(#"C:\Users\398780\Desktop\Nikita\movie.xml");
mm=(Movie)deserializer.Deserialize(textReader);
textReader.Close();
return mm;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Window1 win1 = new Window1();
win1.Show();
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Window2 win2 = new Window2();
win2.Show();
}
}
}
MVVM-movie.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace SerializeDeSerialize
{
public class Movie
{
private string _title;
private int _rating;
private DateTime _releaseDate;
public Movie()
{
}
public string Title
{
get { return _title; }
set { _title = value; }
}
public int Rating
{
get { return _rating; }
set { _rating = value; }
}
public DateTime ReleaseDate
{
get { return _releaseDate; }
set { _releaseDate = value; }
}
}
}
Please check..it is same as you told or not?
I am trying to make a very easy UserControl that has a path that you can type in a textbox or that you can find by clicking a browse button.
I tried to do this with a dependency property but this doesn't work completely when binding to it.
Here my xaml:
<UserControl x:Class="PathSelector.PathSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PathSelector">
<DockPanel Height="28">
<Button DockPanel.Dock="Right" Padding="5" Margin="5 0 0 0"
FontWeight="Bold"
Content="..."
Click="BrowseButton_Click" />
<Grid>
<TextBox
HorizontalAlignment="Stretch" VerticalAlignment="Center"
x:Name="SelectedPathTxtBox"
LostKeyboardFocus="SelectedPathTxtBox_LostKeyboardFocus" />
</Grid>
</DockPanel>
</UserControl>
And this is the codebehind:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
namespace PathSelector
{
/// <summary>
/// A simple input for path, with browse button
/// </summary>
public partial class PathSelector : UserControl
{
public PathSelector()
{
InitializeComponent();
}
private void BrowseButton_Click(object sender, RoutedEventArgs e)
{
System.Windows.Forms.OpenFileDialog fileDialog = new System.Windows.Forms.OpenFileDialog();
fileDialog.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*";
if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
SelectedPathTxtBox.Text = fileDialog.FileName;
}
}
#region Dependency Properties
public string SelectedPath
{
get { return (string)GetValue(SelectedPathProperty); }
set { SetValue(SelectedPathProperty, value); }
}
public static readonly DependencyProperty SelectedPathProperty =
DependencyProperty.Register(
"SelectedPath",
typeof(string),
typeof(PathSelector),
new FrameworkPropertyMetadata(new PropertyChangedCallback(SelectedPathChanged))
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
});
private static void SelectedPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MessageBox.Show("Changed!");
// How to update the values here??
}
#endregion
private void SelectedPathTxtBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
SelectedPath = SelectedPathTxtBox.Text;
}
}
}
I want to use this UserControl like this later:
<pathselector:PathSelector
SelectedPath="{Binding PathToSomeFile}"/>
"PathToSomeFile" is a string variable in the ViewModel that should be updated in both directions.
How can I achieve this? What am I missing?
Thanks a lot!
Modify SelectedPathChanged as below:
private static void SelectedPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((PathSelector)d).SelectedPathTxtBox.Text = e.NewValue.ToString();
MessageBox.Show("Changed!");
}
You should bind TextBox Text to your custom DP which will automatically update its source property.
<TextBox HorizontalAlignment="Stretch" VerticalAlignment="Center"
x:Name="SelectedPathTxtBox"
Text="{Binding SelectedPath, RelativeSource={RelativeSource
Mode=FindAncestor, AncestorType=UserControl}}"/>
Also you don't need to handle LostFocus, since Text default UpdateSourceTrigger value is LostFocus. It will update the binding property SelectedPath on lost focus.
And since SelectedPath, default UpdateSourceTrigger value is PropertyChanged, it will update PathToSomeFile whenever property changes.
If you just miss the both direction part, you can use:
<pathselector:PathSelector SelectedPath="{Binding PathToSomeFile, Mode=TwoWay}" />
More info here:
MSDN Binding.Mode Property
I have a user control that contains two text boxes, as well as some other controls. I want to be able to drag/drop a complex type onto this control, and I want the entire control to be a drop target, including the textboxes and space around the composited controls. When the data is dropped, it is split apart into component fields, each represented by the controls in the user control.
The problem I am having is that the textboxes (if I set AllowDrop to true) are trying to do their own drag drop thing, and will individually accept only the text format of the drop data. If I set AllowDrop to false on the textboxes, the drop is disabled the for the textboxes altogether. I can drag my complex data to labels, checkboxes etc, and it behaves exactly like I expect it should.
In addition the space around the other controls does not seem to be considered a valid drop target.
Any ideas how to make the text boxes behave as the controls (such as the labels, checkbox or combobox), and why the grid is not being considered a valid drop target?
Source for the user control:
<UserControl x:Class="DragDropTester.CompositeControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="226" d:DesignWidth="428" AllowDrop="True">
<Grid AllowDrop="True">
<TextBox Height="23" Margin="115,12,12,0" Name="textBox1" VerticalAlignment="Top" AllowDrop="False" />
<Label Content="TextBox 1:" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="label1" VerticalAlignment="Top" Width="97" />
<TextBox Height="23" Margin="115,41,12,0" Name="textBox2" VerticalAlignment="Top" AllowDrop="False" />
<Label Content="TextBox 2:" Height="28" HorizontalAlignment="Left" Margin="12,41,0,0" Name="label2" VerticalAlignment="Top" Width="97" />
<CheckBox Content="CheckBox" Height="16" Margin="115,70,150,0" Name="checkBox1" VerticalAlignment="Top" />
<ComboBox Height="23" Margin="115,92,12,0" Name="comboBox1" VerticalAlignment="Top" />
</Grid>
</UserControl>
and code behind:
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;
namespace DragDropTester {
/// <summary>
/// Interaction logic for CompositeControl.xaml
/// </summary>
public partial class CompositeControl : UserControl {
public CompositeControl() {
InitializeComponent();
PreviewDragEnter += new DragEventHandler(CompositeControl_DragEnter);
this.PreviewDragOver += new DragEventHandler(CompositeControl_DragEnter);
Drop += new DragEventHandler(CompositeControl_Drop);
}
void CompositeControl_Drop(object sender, DragEventArgs e) {
var complex = e.Data.GetData("ComplexDragData") as ComplexDragData;
if (complex != null) {
this.textBox1.Text = complex.Text1;
this.textBox2.Text = complex.Text2;
this.checkBox1.IsChecked = complex.BoolValue;
}
}
void CompositeControl_DragEnter(object sender, DragEventArgs e) {
var complex = e.Data.GetData("ComplexDragData") as ComplexDragData;
if (complex != null) {
e.Effects = DragDropEffects.Link;
} else {
e.Effects = DragDropEffects.None;
}
e.Handled = true;
}
}
}
And for the main window that hosts the user control and a drag source...
XAML:
<Window x:Class="DragDropTester.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:DragDropTester"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<src:CompositeControl />
<Label Content="Drag Source" Grid.Row="1" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="5" Background="LightGray" Name="lblDragSource" />
</Grid>
</Window>
C# code behind:
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;
namespace DragDropTester {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
private Point _startPoint;
private bool _IsDragging;
public MainWindow() {
InitializeComponent();
lblDragSource.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(lblDragSource_PreviewMouseLeftButtonDown);
lblDragSource.PreviewMouseMove += new MouseEventHandler(lblDragSource_PreviewMouseMove);
}
void lblDragSource_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
_startPoint = e.GetPosition(sender as IInputElement);
}
void lblDragSource_PreviewMouseMove(object sender, MouseEventArgs e) {
if (_startPoint == null) {
return;
}
if (e.LeftButton == MouseButtonState.Pressed && !_IsDragging) {
Point position = e.GetPosition(sender as IInputElement);
if (Math.Abs(position.X - _startPoint.X) > SystemParameters.MinimumHorizontalDragDistance || Math.Abs(position.Y - _startPoint.Y) > SystemParameters.MinimumVerticalDragDistance) {
StartDrag(sender as DependencyObject);
}
}
}
private void StartDrag(DependencyObject dragSource) {
var data = new DataObject();
var dragData = new ComplexDragData { Text1 = "This is text1", Text2 = "This is text2", BoolValue = true };
data.SetData("ComplexDragData", dragData);
data.SetData(DataFormats.Text, dragData.ToString());
try {
_IsDragging = true;
DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Copy | DragDropEffects.Link);
} finally {
_IsDragging = false;
}
}
}
public class ComplexDragData {
public String Text1 { get; set; }
public String Text2 { get; set; }
public bool BoolValue { get; set; }
public override string ToString() {
return string.Format("text1: {0} text2: {1} Bool: {2}", Text1, Text2, BoolValue );
}
}
}
Its looks like I can get the behavior I want by hooking the drag/drop events of the text boxes individually:
public CompositeControl() {
InitializeComponent();
PreviewDragEnter += new DragEventHandler(CompositeControl_DragEnter);
PreviewDragOver += new DragEventHandler(CompositeControl_DragEnter);
textBox1.PreviewDragEnter += new DragEventHandler(textBox_PreviewDragEnter);
textBox1.PreviewDragOver += new DragEventHandler(textBox_PreviewDragEnter);
textBox1.PreviewDrop += new DragEventHandler(CompositeControl_Drop);
textBox2.PreviewDragEnter += new DragEventHandler(textBox_PreviewDragEnter);
textBox2.PreviewDragOver += new DragEventHandler(textBox_PreviewDragEnter);
textBox2.PreviewDrop += new DragEventHandler(CompositeControl_Drop);
Drop += new DragEventHandler(CompositeControl_Drop);
}
void textBox_PreviewDragEnter(object sender, DragEventArgs e) {
e.Handled = true;
}
I'm here 8 years later to say this helped me. The MVVM version of this:
XAML
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewDragEnter">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewDragOver">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxIgnore"/>
</i:EventTrigger>
<i:EventTrigger EventName="PreviewDrop">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="TextBoxDrop"/>
</i:EventTrigger>
</i:Interaction.Triggers>
ViewModel
public void TextBoxIgnore(object sender, DragEventArgs args)
{
args.Handled = true;
}
public void TextBoxDrop(object sender, DragEventArgs args)
{
// handle the drop here.
}
Note: Using the following...
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"