Is it possible to change sender's property in event?
I have my own control in wpf with 10 Image controls.
I set on all of them mouse enter and mouse leave events.
All those events do the same(change size and Z index) but for specific Image.
With changing sender's property in event I will have only 2 event's methods, not 20.
When I tried to change sender's property I saw it was readonly.
Is it possible to do ?
Point all your controls at the same handlers. You can do this at design time or through code.
In the handler cast sender to the type of control.
Now when you change it's properties, you are changing the properties of the control that raised the event
PS don't forget to check to see if the cast is valid, before you try to access it's members.
Here how you can do it in xaml
/ <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void image1_MouseEnter(object sender, MouseEventArgs e)
{
//put your code here and all your images will points here
}
private void image1_MouseLeave(object sender, MouseEventArgs e)
{
//put your code here and all your images will points here
}
}
<Window x:Class="WpfApplication2.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>
<Image Height="51" HorizontalAlignment="Left" Margin="91,116,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="61" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
<Image Height="51" HorizontalAlignment="Left" Margin="91,116,0,0" Name="image2" Stretch="Fill" VerticalAlignment="Top" Width="61" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
<Image Height="51" HorizontalAlignment="Left" Margin="91,116,0,0" Name="image3" Stretch="Fill" VerticalAlignment="Top" Width="61" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
<Image Height="51" HorizontalAlignment="Left" Margin="91,116,0,0" Name="image4" Stretch="Fill" VerticalAlignment="Top" Width="61" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
</Grid>
</Window>
//and here in code behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
image1.MouseEnter += image1_MouseEnter;
image2.MouseEnter += image1_MouseEnter;
image3.MouseEnter += image1_MouseEnter;
image4.MouseEnter += image1_MouseEnter;
image1.MouseEnter += image1_MouseLeave;
image2.MouseEnter += image1_MouseLeave;
image3.MouseEnter += image1_MouseLeave;
image4.MouseEnter += image1_MouseLeave;
}
private void image1_MouseEnter(object sender, MouseEventArgs e)
{
}
private void image1_MouseLeave(object sender, MouseEventArgs e)
{
}
}
Related
My window architecture is a Mainwindow.xaml which contains many usercontrols ie: Pesos.xaml and Materiales.xaml. The problem is when the user clicks over any "Materiales.xaml" component, the focused TextBox element in "Pesos.xaml" loses the focus.
I tried to add a public property which returns the Textbox of "Pesos" usercontrol about im interested on with no success.
By the moment is enaugh for me that when the keyup event be throwed by the "Materiales" usercontrol, the focus goes to "Pesos" usercomponent TextBox. This is Pesos.cs.xaml, at first you can see BuscadorTexto public property in order to access it from out of the usercontrol. Secondly, I have the UserControl_GotFocus() which it will throw an exception when the focus is received from Materiales user control due to the DataContext is null:
public partial class Pesos : UserControl
{
public Pesos()
{
InitializeComponent();
}
bool txtPesoFocus = false;
public TextBox BuscadorTexto {
get { return this.txtBuscador; }
}
...
private void UserControl_GotFocus(object sender, RoutedEventArgs e)
{
if (!((ViewModel.PuestoViewModel)DataContext).IsMaterialValido.GetValueOrDefault())
this.txtBuscador.Focus();
else if (((ViewModel.PuestoViewModel)DataContext).IsMaterialValido.GetValueOrDefault()
&& ((ViewModel.PuestoViewModel)DataContext).SelectedBascula.Tipo == Comun.TipoMaquina.Manual)
txtPeso.Focus();
}
}
And this is Materiales.cs:
<UserControl x:Class="A99.AsuaProducts.Ensayos.Controles.Puestos.OfMateriales"
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:A99.AsuaProducts.Ensayos.Controles.Puestos"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:controls="http://metro.mahapps.com/winfx/xaml/controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" >
<Grid>
<Grid.RowDefinitions>
...
</Grid.RowDefinitions>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
</Grid>
<DataGrid x:Name="MetroDataGrid"
ItemsSource="{Binding ListaOfIteracionMaterialesMaquina}"
SelectedItem="{Binding SelectedOfIteracionMaterial}"
Grid.Row="1"
Margin="2"
AutoGenerateColumns="False"
HeadersVisibility="All"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserReorderColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
CanUserResizeColumns="False"
IsReadOnly="True"
SelectionUnit="FullRow"
Focusable="False"
KeyUp="MetroDataGrid_KeyUp">
<DataGrid.Columns>
...
</DataGrid.Columns>
</DataGrid>
...
</UserControl>
This is the Materiales code behind:
public partial class OfMateriales : UserControl
{
public OfMateriales()
{
InitializeComponent();
}
private void Button_GotFocus(object sender, RoutedEventArgs e)
{
MessageBox.Show("Ojo que siguiente tiene el foco");
}
private void MetroDataGrid_KeyUp(object sender, KeyEventArgs e)
{
Pesos uc = new Pesos();
uc.BuscadorTexto.Text = "KK";
uc.BuscadorTexto.Focus();
}
}
As you can see, I tried to edit the textBox content and set the focus but no effect at all.
You have to create a new focus scope targeting the Materiales control. This way focusing child elements of the Materiales control won't steal the keyboard focus from the TextBox (or any other control inside the main focus scope) anymore.
You use the FocusManager to create a new focus scope:
MainWindow.xaml
<Window>
<StackPanel>
<TextBox />
<!--
A separate focus scope will prevent the user control
from stealing focus of any element inside the MainWindow focus scope
-->
<Materiales FocusManager.IsFocusScope="True" />
</StackPanel>
</Window>
I have a method in my view model. How I can bind this method to textbox.gotfocus property.
My XAML part is:
<TextBox Style=
"{StaticResource TextBoxHadnigPanel}"
GotFocus="{Binding GotFocusCustomerNameMethod}"
LostFocus="{Binding LostFocusCustomerNameMethod}"
x:Name="TextBoxCustomerName"
Grid.Row="0"
Grid.Column="1"
MaxLength="16"
Margin="10" />
How to bind this LostFocus and GotFocus properties?
Anyone?
Thanks in advance
You can't bind a method in WPF.
Alternative: You can use a Behavior for a TextBox with MVVM.
You need a reference to System.Windows.Interactivity to achieve this.
public class TextBoxFocusBehavior : Behavior<TextBox>
{
#region Overrides of Behavior
protected override void OnAttached()
{
AssociatedObject.GotFocus += AssociatedObject_GotFocus;
AssociatedObject.LostFocus += AssociatedObject_LostFocus;
base.OnAttached();
}
private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
{
//TODO Your LostFocus Method here.
}
private void AssociatedObject_GotFocus(object sender, RoutedEventArgs e)
{
//TODO Your GotFocus Method here.
}
#endregion
}
Xaml:
You need a reference in the xaml file:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:behaviors="clr-namespace:YourNamespace"
<TextBox Style="{StaticResource TextBoxHadnigPanel}"
x:Name="TextBoxCustomerName"
Grid.Row="0"
Grid.Column="1"
MaxLength="16"
Margin="10">
<i:Interaction.Behaviors>
<behaviors:TextBoxFocusBehavior />
</i:Interaction.Behaviors>
</TextBox>
What I am trying to make: I want to click on a button that lets me name my item. The item is then added to the listview.
So far the only way I can add an item is if I directly name it in the code.
Here is my code so far:
private void button_add(object sender, RoutedEventArgs e)
{
ListViewItem item = new ListViewItem();
item.Content = "randommmmm";
list1.Items.Add(item);
}
Here is a very basic example that should give you the idea.
MainWindow.xaml.cs:
public partial class MainWindow: Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
}
private void txt_PreviewKeyDown(object sender, KeyEventArgs e)
{
if(e.Key == Key.Enter)
{
list1.Items.Add(txt.Text);
txt.Text = string.Empty;
popup.IsOpen = false;
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.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:WpfApplication1"
mc:Ignorable="d"
Title="Window6" Height="300" Width="300">
<StackPanel>
<ListView x:Name="list1" />
<Popup x:Name="popup" Width="300" PlacementTarget="{Binding ElementName=btn}">
<Border Background="White" BorderBrush="AliceBlue" BorderThickness="2">
<TextBox x:Name="txt" Margin="10" PreviewKeyDown="txt_PreviewKeyDown" />
</Border>
</Popup>
<Button x:Name="btn" Content="Add" Click="Button_Click" />
</StackPanel>
</Window>
Clicking on the Button displays a Popup with a TextBox and when you press [Enter] the text in the TextBox is added to the ListView.
If you are serious about WPF and XAML I really recommend you to learn the MVVM design pattern but that's another story :)
You can bind a TextBox to a property in your view model.
<TextBox Text="{Binding ItemName}" />
private string itemName;
public string ItemName
{
get { return itemName; }
set
{
if (value == null || value == itemName) return;
itemName = value;
NotifyOnPropertyChanged(nameof(ItemName));
}
}
So you can use ItemName to create your item.
item.Content = ItemName;
I have a simple UserControl that I want to display in my stackpanel programmatically
.
When I do, the UC does not show on the screen. If I drag a single instance from the toolbox it works fine.
The User Control is XAML is
<UserControl x:Class="MYProj.Controls.SpecialNumberOption"
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"
d:DesignHeight="300" d:DesignWidth="200">
<Viewbox>
<Grid x:Name="LayoutRoot" Background="White" Width="200" Height="300">
<Button x:Name="buttonMe" Content="Button" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="180" Height="150" Style="{StaticResource NumberButtonStyle}" Click="buttonMe_Click"/>
<TextBlock x:Name="subText" HorizontalAlignment="Left" Margin="10,165,0,0" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Height="125" Width="180" FontStyle="Italic" TextAlignment="Center"/>
</Grid>
</Viewbox>
</UserControl>
The Codebehind
public partial class SpecialNumberOption : UserControl
{
public event RoutedEventHandler Click;
public SpecialNumberOption()
{
InitializeComponent();
this.applyStyle();
}
public SpecialNumberOption(SurveyQuestionOption option)
{
this.buttonMe.Content = option.Text;
this.subText.Text = option.SubText;
this.applyStyle();
}
private void applyStyle()
{
this.buttonMe.FontSize = 26;
this.buttonMe.Background = standardBackground;
this.buttonMe.Foreground = standardForecolor;
}
///Raise the event to the outside
private void buttonMe_Click(object sender, RoutedEventArgs e)
{
Click(this, e);
}
}
Implementation
This is how Im adding the control
foreach (var y in x.Options)
{
//Create new instance from An object
var r = new SpecialNumberOption(y);
// Set visibility
r.Visibility = System.Windows.Visibility.Visible;
r.IsEnabled = false;
//Assign the event handler
r.Click += r_Click;
//This is my stackpanel
listOptions.Children.Add(r);
....
}
//Handle the click event
void r_Click(object sender, RoutedEventArgs e)
{
SpecialNumberOption o = (SpecialNumberOption)e.OriginalSource;
....
}
Update
I found when I use the alternate Constructor this is when it ceases to work.
I have to use the default constructor. Is this normal?
I have not checked all of your posted code for correctness but here is the issue with your constructors: you must call InitializeComponent (and it must happen before you access any named elements)
here is a version with a fix:
public SpecialNumberOption()
{
InitializeComponent();
this.applyStyle();
}
public SpecialNumberOption(SurveyQuestionOption option) : this () //will call the empty default constructor
{
this.buttonMe.Content = option.Text;
this.subText.Text = option.SubText;
}
Remark: I consider it bad style for controls to have more than the empty default constructor.
The parameters should be set via a property setter. It enable you and whoever will be reusing your control to use and parameterize it in xaml.
I am having a problem in my project. This is my Solution Explorer:
BLA is an example UserControl that is loaded twice into a MainWindow Grid:
<Window x:Class="UserControlWechseln.MainWindow"
xmlns:local="clr-namespace:UserControlWechseln"
Title="MainWindow" Height="428" Width="1195" xmlns:am="http://schemas.amcharts.com/charts/wpf/2009/xaml">
<Grid Height="1000" Width="1000">
<Grid Height="500" HorizontalAlignment="Left" Margin="12,31,0,0" Name="grid1" VerticalAlignment="Top" Width="142">
<local:BLA Margin="-3,-17,-270,17" />
</Grid>
<Grid Height="500" HorizontalAlignment="Right" Margin="0,6,31,0" Name="grid2" VerticalAlignment="Top" Width="402">
<local:BLA />
</Grid>
</Grid>
</Window>
The XAML Code for the BLA UserControl looks like this:
<UserControl x:Class="UserControlWechseln.BLA"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Name="Bla">
<Button Content="House" Height="23" HorizontalAlignment="Left" Margin="64,237,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="ButtonClick" />
<Button Content="Soccer" Height="23" HorizontalAlignment="Left" Margin="169,237,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="ButtonClick" />
</Grid>
</UserControl>
And the C# Code for the BLA UserControl looks like this:
public partial class BLA : UserControl {
public BLA() {
InitializeComponent();
}
private void ButtonClick(object sender, RoutedEventArgs e) {
Button btn = sender as Button;
Bla.Children.Clear();
if (btn.Content.ToString() == "House") {
Haus uc1 = new Haus();
Bla.Children.Add(uc1);
} else if (btn.Content.ToString() == "Soccer") {
Fussball uc2 = new Fussball();
Bla.Children.Add(uc2);
}
}
private void Window_Loaded(object sender, RoutedEventArgs e) {
}
private void button1_Click(object sender, RoutedEventArgs e) {
}
private void button1_Click_1(object sender, RoutedEventArgs e) {
}
private void button1_Click_2(object sender, RoutedEventArgs e) {
}
private void button2_Click(object sender, RoutedEventArgs e) {
}
}
}
The problem now is that you get this view:
Is it possible to trigger the Home Button once and the Img in displays on both UserControls "BLA"? They obviously are the same UserControl.
Thanks for your help.
They are different instances of your UserControl, they do not know that the other exists. You are going to need to create Properties and Events. I am sure there is probably a better way of it but here is something I threw together to demonstrate( I also renamed some of your classes because I do not have the same Namespaces that you have). Also you are clearing all of the controls out of your UserControl when you change your image.
Edit added complete example
UserControl
namespace WpfApplication1{
/// <summary>
/// Interaction logic for Bla.xaml
/// </summary>
public partial class Bla : UserControl
{
public event RoutedEventHandler changeHaus
{
add { AddHandler(myEvents.changeHausEvent, value); }
remove { RemoveHandler(myEvents.changeHausEvent, value); }
}
public event RoutedEventHandler changeSoccer
{
add { AddHandler(myEvents.changeSoccerEvent, value); }
remove { RemoveHandler(myEvents.changeSoccerEvent, value); }
}
public Bla()
{
InitializeComponent();
}
private void ButtonClick(object sender, RoutedEventArgs e) {
Button btn = sender as Button;
if (btn.Content.ToString() == "House")
{
SetHaus();
RoutedEventArgs ea = new RoutedEventArgs(myEvents.changeHausEvent);
RaiseEvent(ea);
}
else if (btn.Content.ToString() == "Soccer")
{
SetSoccer();
RoutedEventArgs ea = new RoutedEventArgs(myEvents.changeSoccerEvent);
RaiseEvent(ea);
}
}
public void SetHaus()
{
display.Fill = new SolidColorBrush(Colors.Blue);
}
public void SetSoccer()
{
display.Fill = new SolidColorBrush(Colors.Red);
}
}
public static class myEvents
{
public static RoutedEvent changeHausEvent = EventManager.RegisterRoutedEvent("changeHaus",RoutingStrategy.Tunnel,typeof(RoutedEventHandler), typeof(Bla));
public static RoutedEvent changeSoccerEvent = EventManager.RegisterRoutedEvent("changeSoccer", RoutingStrategy.Tunnel, typeof(RoutedEventHandler), typeof(Bla));
}
}
UserControl Xaml
<UserControl x:Class="WpfApplication1.Bla"
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="300" d:DesignWidth="300">
<Grid Name="bla">
<Grid.RowDefinitions>
<RowDefinition Height="3*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Name="display" Height="223" Grid.Row="0" />
<Button Grid.Row="1" Content="House" Height="23" HorizontalAlignment="Left" Margin="64,25,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="ButtonClick" />
<Button Grid.Row="1" Content="Soccer" Height="23" HorizontalAlignment="Left" Margin="169,25,0,0" Name="button2" VerticalAlignment="Top" Width="75" Click="ButtonClick" />
</Grid>
</UserControl>
Main Window
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void bla1_changeHaus(object sender, RoutedEventArgs e)
{
bla2.SetHaus();
}
private void bla1_changeSoccer(object sender, RoutedEventArgs e)
{
bla2.SetSoccer();
}
private void bla2_changeHaus(object sender, RoutedEventArgs e)
{
bla1.SetHaus();
}
private void bla2_changeSoccer(object sender, RoutedEventArgs e)
{
bla1.SetSoccer();
}
}
}
MainWindow Xaml
<Window x:Class="WpfApplication1.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" xmlns:my="clr-namespace:WpfApplication1">
<Grid>
<my:Bla HorizontalAlignment="Left" Margin="0,12,0,0" x:Name="bla1" VerticalAlignment="Top" changeHaus="bla1_changeHaus" changeSoccer="bla1_changeSoccer" />
<my:Bla HorizontalAlignment="Left" Margin="247,12,0,0" x:Name="bla2" VerticalAlignment="Top" changeHaus="bla2_changeHaus" changeSoccer="bla2_changeSoccer" />
</Grid>
</Window>