Restore previous session after automatic log off in WPF - c#

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?

Related

WPF C# get Object properties without adding extra variables into the viewmodel

I'm curently trying to implemnt a Combobox binding to a list and some labels showing the details of a selected object. The binding to the Combobox works without any problems but I don't want to add extra variables into my ViewModel just to display the name and speed of my car objects.
Is there any way to Map the object variables of the selected combobox item on to the labels without adding additional variables into my ViewModel?
That's the code I'm currently working with
MainWondow.xaml.cs
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;
namespace StackOF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModel viewModel;
public MainWindow()
{
viewModel = new ViewModel();
DataContext = viewModel;
InitializeComponent();
}
}
}
ViewModel.cs
using _02_WPFCarInfo.AutoKlassen;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace StackOF
{
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<AutoModel> _autoModels;
private AutoModel selectedModel;
public ObservableCollection<AutoModel> AutoModels
{
get { return _autoModels; }
set
{
_autoModels = value;
OnPropertyChanged();
}
}
public AutoModel SelectedModel
{
get { return selectedModel; }
set
{
selectedModel = value;
OnPropertyChanged();
}
}
public ViewModel()
{
_autoModels = generateCars();
}
private ObservableCollection<AutoModel> generateCars()
{
AutoModel model1 = new AutoModel();
AutoModel model2 = new AutoModel();
AutoModel model3 = new AutoModel();
model1.name = "Mercedes C12 Pro";
model1.speed = "125 km\\h";
model2.name = "Audi A12";
model2.speed = "236 km\\h";
model3.name = "Audi S20 Pro";
model3.speed = "300 km\\h";
ObservableCollection<AutoModel> cars = new ObservableCollection<AutoModel>();
cars.Add(model1);
cars.Add(model2);
cars.Add(model3);
return cars;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
MainWindow.xaml
<Window x:Class="StackOF.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:StackOF"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<ComboBox SelectedItem="{Binding SelectedModel}" DisplayMemberPath="name" ItemsSource="{Binding AutoModels}" HorizontalAlignment="Center" Margin="0,164,0,0" VerticalAlignment="Top" Width="212"/>
<Label Content="Name:" HorizontalAlignment="Left" Margin="294,231,0,0" VerticalAlignment="Top"/>
<Label Content="Speed:" HorizontalAlignment="Left" Margin="294,262,0,0" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="---" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
<TextBlock HorizontalAlignment="Center" Margin="0,267,0,0" TextWrapping="Wrap" Text="---" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
</Grid>
</Window>
AutoModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _02_WPFCarInfo.AutoKlassen
{
public class AutoModel
{
public String name { get; set; }
public String speed { get; set; }
public AutoModel()
{
this.speed = String.Empty;
this.name = String.Empty;
}
public AutoModel(String name, String speed)
{
this.speed = speed;
this.name = name;
}
}
}
I thought about something like :
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
<TextBlock HorizontalAlignment="Center" Margin="0,267,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.speed}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
But obviously it is not possible to select the variables of "SelectedModel" that way.
Ok nvm it DOES work. It only does not work if you have a textblock with opening and closing tag with text inbetween
This works:
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303"/>
but this doesn't
<TextBlock HorizontalAlignment="Center" Margin="0,241,0,0" TextWrapping="Wrap" Text="{Binding SelectedModel.name}" VerticalAlignment="Top" RenderTransformOrigin="0.287,-1.303">---</TextBlock>

How can I make button visible when Registration was successful?

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

WPF - Bind between two CheckBoxes' Content with a Label.Content in two different windows

I have two windows in my project(MainWindow and one small window for some properties of controls of the MainWindow). In one Tab in the MainWindow there is a Grid divided to ten Columns. In each Column there are some Controls. Below is a sample code of my project.
I want if I check the Period(CheckBox in PropertiesWindow) the Label(MainWindow) to be "Period" and when I check the Frequency(CheckBox in PropertiesWindow) the Label(MainWindow) to be "Frequency".
I want, when I check one of the checkboxes at the PropertiesWindow (Period or Frequency), the Label (lb_freq1) at the MainWindow to change its Content according to the Content of the checked CheckBox. (Moreover, the selected units to be displayed at the time_div1(Label)).
FIRST SOLUTION:
XAML MainWindow:
<Window x:Class="wpf1.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-wpf1"
mc:Ignorable="d"
Title="wpf1" Height="720" Width="1280" WindowStartupLocation="CenterScreen" Icon="kkk.bmp" Background="#FFE0E0E0" Foreground="#FF49A81D" BorderBrush="#FFB93838" >
<Grid>
<TabControl x:Name="tabControl">
<TabItem Header="Tab1">
<Grid>
<StackPanel>
<Label x:Name="lb_freq1" Content="Period" HorizontalAlignment="Center" Margin="0,10,0,0" />
<StackPanel Orientation="Horizontal" Margin="0" HorizontalAlignment="Center">
<TextBox x:Name="txt_freq1" Width="50" Height="20" HorizontalContentAlignment="Right" BorderThickness="1,1,0,1" HorizontalAlignment="Left" VerticalContentAlignment="Center"/>
<Label x:Name="time_div1" Content="us" Width="20" BorderThickness="0,1,1,1" Margin="0" HorizontalAlignment="Right" Height="20" Padding="0" BorderBrush="#FFABADB3" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" />
</StackPanel>
<Label x:Name="lb_width1" Content="Pulse Width" HorizontalAlignment="Center" Margin="0,10,0,0" />
<StackPanel Orientation="Horizontal" Margin="0" HorizontalAlignment="Center">
<TextBox x:Name="txt_width1" Width="50" Height="20" HorizontalContentAlignment="Right" BorderThickness="1,1,0,1" HorizontalAlignment="Left"/>
<Label x:Name="pv_div1" Content="us" Width="20" BorderThickness="0,1,1,1" Margin="0" HorizontalAlignment="Right" Height="20" Padding="0" BorderBrush="#FFABADB3" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" />
</StackPanel>
<Button x:Name="Properties1" Content="Properties" Margin="10,30,10,10" HorizontalAlignment="Center" BorderBrush="Blue" Click="Properties1_Click" />
</StackPanel>
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
EDITED
Code Behind MainWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;
using System.Threading;
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.Globalization;
using System.ComponentModel;
namespace wpf1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
ViewModel viewModel = new ViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
}
private void Properties1_Click(object sender, RoutedEventArgs e)
{
string res1 = lb_freq1.Content.ToString();
string res3 = time_div1.Content.ToString();
var newWindow = new PWMProperties();
newWindow.Owner = this;
newWindow.ShowDialog();
string result1 = newWindow.Value1;
if (result1 == null)
{
lb_freq1.Content = res1;
}
else
{
lb_freq1.Content = result1;
}
string result3 = newWindow.Unit1;
if (result3 == null)
{
time_div1.Content = res3;
}
else
{
time_div1.Content = result3;
}
}
}
}
XAML PropertiesWindow:
<Window x:Class="wpf1.PWMProperties"
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:wpf1"
mc:Ignorable="d"
Title="Properties" Height="335" Width="285" ResizeMode="NoResize" BorderThickness="0" WindowStartupLocation="CenterOwner">
<Window.Resources>
<local:BoolConverter2 x:Key="Converter"></local:BoolConverter2>
<local:BoolConverter x:Key="Reverse"></local:BoolConverter>
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Top" Margin="0,10,0,0" HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal" Margin="0,0,0,20">
<StackPanel Margin="0,0,49,0">
<RadioButton x:Name="SelectPeriod" Content="Period" Margin="0,0,0,0" Click="SelectPeriod_Click" />
<ComboBox x:Name="PeriodUnits" Padding="3,2,2,2" IsReadOnly="True" IsEditable="True" Text="us" IsEnabled="{Binding ElementName=SelectPeriod, Path=IsChecked}" SelectionChanged="PeriodUnits_SelectionChanged"
ItemsSource="{Binding PeriodComboBoxItems}">
</ComboBox>
</StackPanel>
<StackPanel Margin="20,0,0,0">
<RadioButton x:Name="SelectFrequency" Content="Frequency" Click="SelectFrequency_Click" />
<ComboBox x:Name="FrequencyUnits" Padding="3,2,2,2" IsReadOnly="True" IsEditable="True" Text="Hz" IsEnabled="{Binding ElementName=SelectFrequency, Path=IsChecked}" SelectionChanged="FrequencyUnits_SelectionChanged"
ItemsSource="{Binding FrequencyComboBoxItems}">
</ComboBox>
</StackPanel>
</StackPanel>
</StackPanel>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="0">
<Button x:Name="OkButton" Content="OK" Margin="135,5,10,5" Click="OkButton_Click" Width="60" />
<Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="60" Margin="0,5,10,5" />
</StackPanel>
</Grid>
</Window>
EDITED
Code Behind PropertiesWindow:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
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;
using System.ComponentModel;
using System.IO;
using System.Xml;
using System.Windows.Markup;
namespace wpf1
{
/// <summary>
/// Interaction logic for Analog.xaml
/// </summary>
public partial class PWMProperties : Window
{
public ObservableCollection<string> PeriodComboBoxItems { get; set; }
public ObservableCollection<string> FrequencyComboBoxItems { get; set; }
public ObservableCollection<string> PulseWidthComboBoxItems { get; set;}
public PWMProperties()
{
InitializeComponent();
this.DataContext = this;
this.PeriodComboBoxItems = new ObservableCollection<string>() { "us", "ms", "s" };
this.FrequencyComboBoxItems = new ObservableCollection<string>() { "Hz", "kHz", "MHz" };
this.PulseWidthComboBoxItems = new ObservableCollection<string>() { "us", "ms", "s" };
}
string val1, val2, unit1, unit2;
private void OkButton_Click(object sender, RoutedEventArgs e)
{
if (SelectPeriod.IsChecked == true)
{
val1 = "Period";
if (unit1 == null || unit1!="ms") unit1 = "us";
}
if (SelectFrequency.IsChecked == true)
{
val1 = "Frequency";
if (unit1 == null || unit1!="kHz") unit1 = "Hz";
}
DialogResult = true;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
}
public string Value1 { get { return val1; } }
public string Value2 { get { return val2; } }
public string Unit1 { get { return unit1; } }
public string Unit2 { get { return unit2; } }
private void PeriodUnits_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
unit1 = PeriodUnits.SelectedItem.ToString();
}
private void FrequencyUnits_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
unit1 = FrequencyUnits.SelectedItem.ToString();
}
}
public class BoolConverter2 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool v = (bool)value;
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotSupportedException();
}
}
}
Second possible solution:
Then, I've added to my MainWindow code a ViewModel:
public class ViewModel : INotifyPropertyChanged
{
private string _value1 = "Period";
public event PropertyChangedEventHandler PropertyChanged;
public string Value1
{
get { return _value1; }
set
{
_value1 = value;
OnPropertyChanged("Value1");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
So, most of the code behind of the PropertiesWindow is deleted and I use Binding for the change of lb_freq1(Label) at the MainWindow.
<Label x:Name="lb_freq1" Content="{Binding Value1, Mode=TwoWay}" HorizontalAlignment="Center" Margin="0,10,0,0" />
I don't know how to continue from that state. I'm new to WPF and C#, and I would be thankful if someone could help me in any way.
MAIN ISSUE
I've edited my first solution, so if someone could take a look. What I managed to do now is almost what i want. But, there is a problem. I want, when I click on the OK.Button, the "settings" I made at Properties.Window should change the Labels at MainWindow. Although, when I click on the Cancel.Button or the Close.Button at the upper right corner, any changes made at the Properties.Window should not change the Labels at MainWindow.
Moreover, when I close the Properties.Window, and then open it again for a second time, the CheckBoxes and ComboBox.SelectedItems need to have the same state they had when the Properties.Window closed. But that doesn't happen.
You should set the DataContext of the two windows properly. Currently, you are setting and overriding it in multiple places. Here is my suggestions:
Use ElementName in your Binding in your windows, i.e., wpf1.PWMProperties and wpf1.MainWindow, whenever you want to Bind to a property in them. In other words, give them a name and Bind to them. For example:
<Window x:Class="wpf1.PWMProperties"
.....
Name="owner">
.....
<StackPanel Margin="0,0,49,0">
.....
ItemsSource="{Binding Path=PeriodComboBoxItems, ElementName=owner}">
</StackPanel>
use DataContext for Binding to Value1 in your ViewModel. Set the DataContext of both Windows to be the instance of your ViewModel:
public partial class MainWindow : Window
{
ViewModel viewModel = new ViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = viewModel;
}
private void Properties1_Click(object sender, RoutedEventArgs e)
{
var newWindow = new PWMProperties();
newWindow.Owner = this;
newWindow.DataContext = viewModel;
newWindow.Show();
}
}

UserControl Data Binding retrieve value

with this simple code:
MainWindows:
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace itemcontrole_lesson
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public class TodoItem
{
public string Username { get; set; }
public int Completion { get; set; }
}
public partial class MainWindow : Window
{
List<TodoItem> items = new List<TodoItem>();
public MainWindow()
{
InitializeComponent();
items.Add(new TodoItem() { Username = "Eric", Completion = 45 });
items.Add(new TodoItem() { Username = "Maxwell", Completion = 80 });
items.Add(new TodoItem() { Username = "Sarah", Completion = 60 });
icTodoList.ItemsSource = items;
}
}
Mainwindows XAML:
<Window x:Class="itemcontrole_lesson.MainWindow"
xmlns:local="clr-namespace:itemcontrole_lesson"
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>
<ItemsControl x:Name="icTodoList">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:UserControl1}">
<local:UserControl1 />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Window>
then a simple UserControle:
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;
namespace itemcontrole_lesson
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
//String CurentUserName = ????????
//Int Progress = ????????
}
private void Button_Click(object sender, RoutedEventArgs e)
{
///hows to remove the user from items in main windows??
}
}
}
UserControle XAML
<UserControl x:Class="itemcontrole_lesson.UserControl1"
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="54.181" Width="399.331">
<Grid Margin="0,0,-155,0">
<Label Content="{Binding Username}" HorizontalAlignment="Left" Margin="23,23,0,0" VerticalAlignment="Top"/>
<Button Content="Close this UC" HorizontalAlignment="Left" Margin="414,22,0,0" VerticalAlignment="Top" Width="119" Click="Button_Click"/>
<ProgressBar HorizontalAlignment="Left" Value="{Binding Completion}" Height="10" Margin="204,23,0,0" VerticalAlignment="Top" Width="154"/>
</Grid>
</UserControl>
Pressing F5 everything will bind ok if you test.
But! how I'm supposed to retrieve my variable value in my usercontrole code?
see where I put comment in UC.
1- I need at least to find a way to remove this control from UI and from Items list?.
2-I'd like access username in my control and set it into a var
any suggestion?
Solution 1:
Use Tag property of button like below:
<Button Content="Close this UC" HorizontalAlignment="Left" Margin="414,22,0,0"
VerticalAlignment="Top" Width="119" Click="Button_Click" Tag="{Binding RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
Event handler:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
List<object> list = (button.Tag as ItemsControl).ItemsSource.OfType<TodoItem>().ToList<object>();
list.Remove(button.DataContext);
(button.Tag as ItemsControl).ItemsSource = list;
}
Solution 2:
More elegant solution:
Create this Style in your MainWindow:
<Window.Resources>
<Style TargetType="Button">
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Window.Resources>
So now the Handler of any Button Click event is in the MainWindow.xaml.cs.
Then change handler definition like below:
private void Button_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
items.Remove(button.DataContext as TodoItem);
icTodoList.ItemsSource = null;
icTodoList.ItemsSource = items;
}

Drag on Drop onto a composite User Control with multiple text boxes

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"

Categories

Resources