Execute command does not fire in resource dictionary code behind - c#

I have created resource dictionary and code behind file for it.
In XAML I have defined command binding and added Executed handler:
<Button Grid.Row="2" Width="100" >
<CommandBinding Command="Search" Executed="CommandBinding_Executed" />
</Button>
Here is code behind:
partial class StyleResources : ResourceDictionary {
public StyleResources() {
InitializeComponent();
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e) {
//this is never executed
}
}
I don't know why is command not executing when button is clicked, and also, why is button enabled when I didn't set CanExecute to true. I have also tried to set it to true, but CanExecute event didn't fire as well.
Here is how I am using the resource dictionary:
public partial class MyWindow : Window {
public MyWindow() {
InitializeComponent();
Uri uri = new Uri("/WPFLibs;component/Resources/StyleResources.xaml", UriKind.Relative);
ResourceDictionary Dict = Application.LoadComponent(uri) as ResourceDictionary;
this.Style = Dict["WindowTemplate"] as Style;
}
}

This is not how you bind commands to buttons. It should look something like this:
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="Search"
Executed="Search_Executed"
CanExecute="Search_CanExecute" />
</Grid.CommandBindings>
...
<Button Grid.Row="2" Width="100" Command="Search" />
...
</Grid>
And in codebehind:
private void Search_Executed(object sender, ExecutedRoutedEventArgs e) {
// do something
}
private void Search_CanExecute(object sender, CanExecuteRoutedEventArgs e) {
e.CanExecute = ...; // set to true or false
}

Related

Click-Event from MainWindow.xaml.cs in App.xaml

so i want to outsource some things from MainWindow.xaml to App.xaml like this for example :
<Application x:Class="SVGTesting.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<DataTemplate DataType="{x:Type ContentControl}" x:Key="Test1">
<StackPanel Orientation="Horizontal">
<Button Content="Button1" Click="Button_Click" x:Name="Button1"/>
<Button Content="Button2" Click="Button_Click" x:Name="Button2"/>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
In MainWindow.xaml then i have something like this
<ContentControl ContentTemplate="{StaticResource Test1}"/>
But now VS says that i cannot use the function "Button_Click" because its not in the codebehind from App.xaml. So how can i call this function from MainWindow in App.xaml?
Is there any way? I don't want answers like MVVM or Command. If it's not possible to solve then WPF is unfortunately useless for me.
Thanks and Greetings.
This is not the easiest thing to do as WPF expect things to be done in its own way. But there's few options, from easiest to hardest.
1. Don't do anything
Easiest way is to keep your data templates inside the MainWindow.xaml.
2. Use Commands instead of event handlers
You currently have event handlers defined like this:
<Button Content="Button1" Click="Button_Click"
"More-WPF way" of doing this would be to replace Click's event handler with a command with this quite cumbersome syntax:
<Button Content="Test" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.OnClickCommand}"></Button>
And then define the command in your MainWindow:
public ICommand OnButtonClick
{
get
{
return new Command(() =>
{
this.Text.Text = "Updated";
});
}
}
3. Define the event handlers in App.xaml.cs and use that to route the event handlers
I don't recommend this as it get tiresome to keep things synced but it's possible. Create and event handler in App.xaml.cs:
public partial class App : Application
{
private void Button_Click(object sender, RoutedEventArgs e)
{
}
}
Then use the sender to access the MainWindow instance and call it's method:
private void Button_Click(object sender, RoutedEventArgs e)
{
var mainWindow = (MainWindow)Window.GetWindow((DependencyObject)sender);
mainWindow.DoWork();
}
In my second example Command is defined like the following:
public class Command : ICommand
{
public delegate void ICommandOnExecute();
private ICommandOnExecute _execute;
public event EventHandler CanExecuteChanged;
public Command(ICommandOnExecute onExecuteMethod)
{
_execute = onExecuteMethod;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_execute?.Invoke();
}
}
You can't do it. See MSDN documentation for Code-Behind:
The event handlers you write must be instance methods defined by the
partial class within the namespace identified by x:Class. You cannot
qualify the name of an event handler to instruct a XAML processor to
look for that handler in a different class scope. You also cannot use
a static method as an event handler.
In WPF you can use a behaviors instead.
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<Button Content="btnWithBehavior">
<i:Interaction.Behaviors>
<local:HandleButtonClick/>
</i:Interaction.Behaviors>
</Button>
public class HandleButtonClick : Behavior<Button>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.Click += AssociatedObject_Click; ;
}
private void AssociatedObject_Click(object sender, RoutedEventArgs e)
{
//Move your MainWindow.Button_Click here;
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.Click -= AssociatedObject_Click;
}
}

How to send TextBox value from modal window to main window programmatically?

I'm trying to learn WPF MVVM I would need to understand how to update a textbox value via a modal window. Below the code, I wrote passes the value to the viewmodel but does not update the textbox. Thanks in advance
UserControl con il TextBox
<TextBox x:Name="Text01UC" Text="{Binding TextUC, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Width="200" Height="33"/>
UserControl Behind
namespace InvioDati
{
public partial class textbox : UserControl
{
public textbox()
{
InitializeComponent();
var vm = new ModelTextView();
this.DataContext = vm;
vm.Load();
}
private void Open_Click(object sender, RoutedEventArgs e)
{
MoadalWindow md = new MoadalWindow();
md.ShowDialog();
}
}
}
ModelTextView
namespace InvioDati
{
class ModelTextView : BaseViewModel
{
private ModelText dati = new ModelText();
public string TextUC
{
get => dati.TextVal;
set
{
dati.TextVal = value;
OnPropertyChanged();
}
}
public void Load() {
TextUC = "GoodMorning";
}
public void Ricevi(string valore)
{
TextUC = valore;
}
}
}
ModalWindow Code behind
namespace InvioDati
{
public partial class MoadalWindow : Window
{
public MoadalWindow()
{
InitializeComponent();
}
private void Test_Click(object sender, RoutedEventArgs e)
{
ModelTextView nd = new ModelTextView();
nd.Ricevi(Send.Text);
this.Close();
}
}
}
Set the DataContext of the ModalWindow to the same instance of ModelTextView in textbox.xaml.cs:
private void Open_Click(object sender, RoutedEventArgs e)
{
MoadalWindow md = new MoadalWindow();
md.DataContext = this.DataContext;
md.ShowDialog();
}
You can then either bind directly to the TextUC property or do the following in ModalWindow.xaml.cs:
private void Test_Click(object sender, RoutedEventArgs e)
{
ModelTextView nd = DataContext as ModelTextView;
nd.Ricevi(Send.Text);
this.Close();
}
You must use a mediator in order not to break mvvm here.
Check https://en.wikipedia.org/wiki/Mediator_pattern#C#
1b. Add Observer pattern to create notifications for value changes.
Dialogs are evil within MVVM, usually you won't need them. What you want is an overlaying View, which can be Data bound in any way as there is no break in the visual tree
If you want to use "dialogs", implement a DialogService to do so.
Edit: here is a draft on how you create something "popup" like in the most simple way:
<UserControl>
<Grid>
<!--Invert visability of all controls below via binding-->
<YourMainControl/>
<Rect Fill="Black" Opacity=".5 Visibility="Hidden"/>
<YourSubControl Visibility="Hidden"/>
</Grid>
</UserControl>

Raise a event on the User control from the Main Window in WPF

There is a textbox in my mainwindow.xaml, when I enter the textbox, I expect the label in my usercontrol, known as View1.xaml will be update accordingly. However I realise the event is not raise at all in the user control when I type the textbox, can you tell me which part is wrong?
The event is able to raise in TextBox_TextChanged_1
my MainWindow.XAML
<Window xmlns:my="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:testapplication" x:Class="testapplication.MainWindow"
Title="MainWindow" Height="964" Width="790">
<Grid >
<Button x:Name="OpenView1" Content="Open Window 1" HorizontalAlignment="Left" Margin="33,70,0,0" VerticalAlignment="Top" Width="111" RenderTransformOrigin="0.279,1.409" Click="OpenView1_Click"/>
<Button x:Name="OpenView2" Content="Open Window 2" HorizontalAlignment="Left" Margin="33,169,0,0" VerticalAlignment="Top" Width="111" Click="OpenView2_Click"/>
<Button x:Name="OpenView3" Content="Open Window 3" HorizontalAlignment="Left" Margin="33,259,0,0" VerticalAlignment="Top" Width="111" Click="OpenView3_Click"/>
<local:View1 x:Name="ViewOne" HorizontalAlignment="Left" Margin="33,332,0,0" VerticalAlignment="Top" Height="226" Width="204" Visibility="Hidden"/>
<local:View2 x:Name="ViewTwo" HorizontalAlignment="Left" Margin="284,332,0,0" VerticalAlignment="Top" Height="226" Width="208" Visibility="Hidden"/>
<local:View3 x:Name="ViewThree" HorizontalAlignment="Left" Margin="534,332,0,0" VerticalAlignment="Top" Height="226" Width="196" Visibility="Hidden"/>
<TextBox HorizontalAlignment="Left" Height="42" Margin="326,70,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="182" FontSize="22" TextChanged="TextBox_TextChanged_1"/>
</Grid>
</Window>
my MainWindow.cs
namespace testapplication
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
//InitializeComponent();
}
//event handler
public event EventHandler<EventArgs> changedText;
private void OpenView1_Click(object sender, RoutedEventArgs e)
{
ViewOne.Visibility = Visibility.Visible;
}
private void OpenView2_Click(object sender, RoutedEventArgs e)
{
ViewTwo.Visibility = Visibility.Visible;
}
private void OpenView3_Click(object sender, RoutedEventArgs e)
{
ViewThree.Visibility = Visibility.Visible;
}
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
if (changedText != null)
{
changedText(this, e);
}
}
}
}
This is my UserControl, known as View1.xaml, it is included in my MainWindow.Xaml
namespace testapplication
{
/// <summary>
/// Interaction logic for View1.xaml
/// </summary>
public partial class View1 : UserControl
{
private MainWindow newWindow = new MainWindow();
public View1()
{
InitializeComponent();
newWindow.changedText += newWindow_ChangeText;
}
void newWindow_ChangeText(object sender, EventArgs e)
{
ViewOnelabel.Content = "Happy";
}
}
}
The problem is my ViewOnelabel.Content = "Happy" did not execute at all, it remain unchanged
There are a few things I would like to point out.
The equivalent of a winforms label in wpf is a TextBlock. A wpf label is actually a type of contentcontrol. Hence the content property.
In wpf there are routed events. These "bubble" up ( and tunnel down ) the visual tree. That means you can handle an event in the window from a control in a usercontrol inside it.
But mainly.
I encourage you to look into the MVVM pattern.
I've put together some code which illustrates these points.
I'd recommend just using binding and mvvm though.
My MainWindow markup:
Title="MainWindow" Height="350" Width="525"
TextBoxBase.TextChanged="Window_TextChanged"
>
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<Label Name="OutputLabel"/>
<TextBlock Text="{Binding OutputString}"/>
<local:UserControl1/>
</StackPanel>
</Grid>
Notice that it handles a textchanged event and because that's routing it will get the event from UserControl1 inside it.
Code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_TextChanged(object sender, TextChangedEventArgs e)
{
OutputLabel.Content = $"Happy {((TextBox)e.OriginalSource).Text}";
}
}
You don't do anything with the text from your textbox in your handler but I have some code there proves you could get at that from mainwindow if you wanted.
My viewmodel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string inputString;
public string InputString
{
get { return inputString; }
set
{
inputString = value;
OutputString = $"{inputString.Length} characters entered";
RaisePropertyChanged();
}
}
private string outputString;
public string OutputString
{
get { return outputString; }
set
{
outputString = value;
RaisePropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Usercontrol1 just has a textbox:
<Grid>
<TextBox Text="{Binding InputString, UpdateSourceTrigger=PropertyChanged}"/>
</Grid>
As you type in that textbox, the text is transferred to the bound property in my viewmodel. That hits the code in my setter. This in turn sets OutputString which is bound to my textblock.
Text changes in both my label and textblock as I type.
Here's a link to my sample on onedrive
https://1drv.ms/u/s!AmPvL3r385QhgpgOPNKPs-veFJ2O3g
The main problem here is that your View1 class is subscribing to an event on a new MainWindow instance, not the MainWindow instance created by your application on start.
Since your MainWindow class has a reference to your View1 class (a named member "ViewOne") you should just change it from the MainWindow class.
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
ViewOne.ViewOneLabel.Content = "Happy";
}
Get rid of the chenagedText event handler and all the code in the View1.xaml.cs... you don't need it.
Note: I am hoping that you are just playing around and learning here... there is no way I would condone building a WPF application in this way.
You could only use the event of the MainPage. I recomment you to add a Property to the UserControl. In my case I call it Text.
public string Text
{
set { ViewOneLabel.Content = value; }
}
In the MainWindow use the Property within the TextChanged Event.
private void TextBox_TextChanged_1(object sender, TextChangedEventArgs e)
{
OpenView1.Text = TextBox.Text;
}
You are creating a new instance of MainWindow in your UserControl. What you want to do is to hook up an event handler to the instance that you actually see on the screen. You can get a reference to this one using the Window.GetWindow method:
public partial class View1 : UserControl
{
public View1()
{
InitializeComponent();
Loaded += (s, e) =>
{
Window mainWindow = Window.GetWindow(this) as MainWindow;
if(mainWindow != null)
mainWindow.changedText += newWindow_ChangeText;
};
}
void newWindow_ChangeText(object sender, EventArgs e)
{
ViewOnelabel.Content = "Happy";
}
}

WPF: How do I use one User control for multiple different Click events

I'm trying to create a User control for all the buttons on my homepage, every user control should have a different Click event. I'm trying to solve this by adding a property to the User control (which works for the label and image) but i can't find any solution for the Click event.
ImageLabelButton.xaml:
<UserControl x:Class="SC.UI.WPF.Controls.ImageLabelButton"
<Grid>
<Button Name="BtnClick">
<StackPanel>
<Image Name="ImageButton"/>
<Label Name="LabelButton"/>
</StackPanel>
</Button>
</Grid>
ImageLabelButton.xaml.cs:
....
<!-- works -->
public string Name
{
get { return this.LabelButton.Content.ToString(); }
set { this.LabelButton.Content = value; }
}
<!-- works -->
public ImageSource SetSource
{
get { return ImageButton.Source; }
set { ImageButton.Source = value; }
}
<!-- doesn't work -->
public EventHandler ButtonAction
{
get { return BtnClick.Click; }
set { BtnClick.Click= value; }
}
Implementation.xaml:
....
<controls:ImageLabelButton Name="first" SetSource="test.png" ButtonAction="Click1"/>
<controls:ImageLabelButton Name="first" SetSource="test.png" ButtonAction="Click2"/>
<controls:ImageLabelButton Name="first" SetSource="test.png" ButtonAction="Click3"/>
You just need to set the event handler up as a property of the user control and set it in the usage code:
User control XAML:
<Grid>
<Button Name="BtnClick" Click="BtnClick_DoClick">
<StackPanel>
<Image Name="ImageButton"/>
<Label Name="LabelButton"/>
</StackPanel>
</Button>
</Grid>
User control codebehind:
public EventHandler<RoutedEventArgs> ButtonAction;
private void BtnClick_DoClick(object sender, RoutedEventArgs e)
{
if (ButtonAction != null) ButtonAction(sender, e);
}
Implementation XAML:
<controls:ImageLabelButton Name="first1" SetSource="test.png" />
<controls:ImageLabelButton Name="first2" SetSource="test.png" />
<controls:ImageLabelButton Name="first3" SetSource="test.png" />
Implementation code behind:
public MainWindow()
{
InitializeComponent();
first1.ButtonAction = Button1;
first2.ButtonAction = Button2;
first3.ButtonAction = Button3;
}
private void Button3(object sender, RoutedEventArgs e) { MessageBox.Show("Pressed 3"); }
private void Button2(object sender, RoutedEventArgs e) { MessageBox.Show("Pressed 2"); }
private void Button1(object sender, RoutedEventArgs e) { MessageBox.Show("Pressed 1"); }
Although you can't set the event handling in XAML this way.
You need a RoutedEvent on your user control that can be accessed from Implementation.xaml
ImageLabelButton.xaml
<Button Name="BtnClick" Click="Submit_Click">
<StackPanel>
<Image Name="ImageButton"/>
<Label Name="LabelButton"/>
</StackPanel>
</Button>
ImageLabelButton.cs
private void Submit_Click(object sender, RoutedEventArgs e)
{
RaiseEvent(new RoutedEventArgs(ClickEvent, this));
}
public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent(
"Click", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyUserControl));
public event RoutedEventHandler Click
{
add { AddHandler(ClickEvent, value); }
remove { RemoveHandler(ClickEvent, value); }
}
Implementation.xaml
<controls:ImageLabelButton Name="first" SetSource="test.png" Click="Click1"/>
Implementation.xaml.cs
private void Click1(object sender, RoutedEventArgs e)
{
}

wpf Usercontrol in usercontrol no response

I have a strange problem in my project. There are pages made from usercontrol and menu bar (also usercontrol).
Here is my usercontrol that contains few buttons
public partial class UpperBar : UserControl
{
public UpperBar()
{
InitializeComponent();
}
public event EventHandler EventbtClicked;
private void btConnect_Click(object sender, System.Windows.RoutedEventArgs e)
{
EventbtClicked(this, e);
}
}
I added this in my page as follows:
<local:UpperBar VerticalAlignment="Top" Grid.Row="0" Height="78" Grid.ColumnSpan="3" Margin="0,2,0,0"/>
And in my page tried to call event:
public PageStatus()
{
InitializeComponent();
Plc.ExecuteRefresh += new EventHandler(RefreshLeds);
UpperBar.EventbtCliced += new EventHandler(UpperBatButtonClick);
}
protected void UpperBarButtonClick(object sender, EventArgs e)
{
//do something
}
But I can't access my event using this UpperBar.EventbtCliced, why ?
You need to access the instance of your class UpperBar in PageStatus, not the class UpperBar itself!
The easiest way for you here:
Name your UpperBar in your XAML, example:
<local:UpperBar x:Name="_myBar" x:FieldModifier="private"/>
Then use this instance in your PageStatus.xaml.cs:
public partial class MainWindow : Window {
public MainWindow()
{
InitializeComponent();
_myBar.EventbtClicked += new EventHandler(UpperBarButtonClick);
}
protected void UpperBarButtonClick(object sender, EventArgs e)
{
//do something
}
}
Now if you are working seriously in WPF, you should really learn about Databinding and MVVM, catching event this way is not the best way to do it at all.
You should use Custom Command (RoutedUICommand) rather than bubbling event from user control.
here are some steps to follow in contrast to your approach:
1: create class myCustomCommand.
namespace WpfApplication1
{
public class myCustomCommand.
{
private static RoutedUICommand _luanchcommand;//mvvm
static myCustomCommand.()
{
System.Windows.MessageBox.Show("from contructor"); // static consructor is called when static memeber is first accessed(non intanciated object)
InputGestureCollection gesturecollection = new InputGestureCollection();
gesturecollection.Add(new KeyGesture(Key.L,ModifierKeys.Control));//ctrl+L
_luanchcommand =new RoutedUICommand("Launch","Launch",typeof(myCustomCommand.),gesturecollection);
}
public static RoutedUICommand Launch
{
get
{
return _luanchcommand;
}
}
}
}
In the xaml of UserControl:
<UserControl x:Class="WpfApplication1.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:CustomCommands="clr-namespace:WpfApplication1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.CommandBindings>
<CommandBinding Command="CustomCommands:myCustomCommand.Launch" Executed="CommandBinding_Executed">
</CommandBinding>
</UserControl.CommandBindings>
<Grid >
<TextBox Name="mytxt" Height="30" Width="60" Margin="50,50,50,50" ></TextBox>
<Button Name="b" Height="30" Width="60" Margin="109,152,109,78" Command="CustomCommands:ZenabUICommand.Launch"></Button>
</Grid>
Now in User control code
Handle command_executed
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
mytxt.Text = "invoked on custom command";
}
}
}

Categories