Expression Blend onLongClick event - c#

I wanna do a very simple thing using Expression Blend (SketchFlow).
I want to have a button in a screen that when it's pressed for more than 3 seconds it should go to another screen.
I thought about using this (green answer):
Button Long Click
within the MouseLeftButtonDown but I don't know how to change to another screen using c# code...just by setting the "Navigate to" option.
So if anyone could tell me how to set a long click behavior in a button so it changes to a new screen it would be great.

Here is a similar but simpler class you can use:
using System;
using System.Collections.Generic;
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;
using System.Windows.Interactivity;
using System.Windows.Threading;
namespace SilverlightApplication14
{
public class LongClickButton : Button
{
public event EventHandler LongClick;
public static DependencyProperty HowLongProperty = DependencyProperty.Register("HowLong", typeof(double), typeof(LongClickButton), new PropertyMetadata(3000.0));
public double HowLong
{
get
{
return (double)this.GetValue(HowLongProperty);
}
set
{
this.SetValue(HowLongProperty, value);
}
}
private DispatcherTimer timer;
public LongClickButton()
{
this.timer = new DispatcherTimer();
this.timer.Tick += new EventHandler(timer_Tick);
}
private void timer_Tick(object sender, EventArgs e)
{
this.timer.Stop();
// Timer elapsed while button was down, fire long click event.
if (this.LongClick != null)
{
this.LongClick(this, EventArgs.Empty);
}
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
this.timer.Interval = TimeSpan.FromMilliseconds(this.HowLong);
this.timer.Start();
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
this.timer.Stop();
}
}
}
With this, you can use any of the standard behaviors in Blend along with the new LongClick event. Set the HowLong property to the number of ms you want (default is 3000) and then use an eventtrigger set to LongClick to trigger your navigation:
<local:LongClickButton Margin="296,170,78,91">
<i:Interaction.Triggers>
<i:EventTrigger EventName="LongClick">
<ei:ChangePropertyAction PropertyName="Background" TargetName="LayoutRoot">
<ei:ChangePropertyAction.Value>
<SolidColorBrush Color="#FFFF1C1C"/>
</ei:ChangePropertyAction.Value>
</ei:ChangePropertyAction>
</i:EventTrigger>
</i:Interaction.Triggers>
</local:LongClickButton>

Related

How to pass a string from a secondary window to the main window in WPF

I am working on a to-do list application for a project. I would like to change the value of a string in an observableCollection. I am able to change the string in the same window but I would like to change the value from a textbox in a secondary window.
So what I tried to do was is change a string in the first window by using a textbox in the second window. By doing the way I have listed below it just blanks out the item I am trying to edit.
I would like to take the test from the textbox in the second window and use it to modify the taskName in the first window. Below I am going to include my code for the two c# files for the windows.
This is the main window but it is called DemoMainWindow:
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 ToDoList.ViewModels;
using ToDoList.Model;
namespace ToDoList
{
/// <summary>
/// Interaction logic for DemoMainWindow.xaml
/// </summary>
public partial class DemoMainWindow : Window
{
private ViewModel _viewModel;
public string? EditedTaskName { get; set; }
public DemoMainWindow()
{
InitializeComponent();
TxtUCEnteredTask.txtLimitedInput.Text = "Do the dishes";
_viewModel = new ViewModel();
DataContext = _viewModel;
}
private void BtnAddTask_Click(object sender, RoutedEventArgs e)
{
_viewModel.Tasks.Add(new TaskModel() { TaskName = TxtUCEnteredTask.txtLimitedInput.Text });
}
private void BtnDeleteTask_Click(object sender, RoutedEventArgs e)
{
if(LstBoxTasks.SelectedItem != null)
{
#pragma warning disable CS8604 // Possible null reference argument.
_ = _viewModel.Tasks.Remove(item: LstBoxTasks.SelectedItem as TaskModel);
#pragma warning restore CS8604 // Possible null reference argument.
}
}
private void BtnHelp_Click(object sender, RoutedEventArgs e)
{
HelpWindow helpWindow = new HelpWindow();
helpWindow.Show();
}
private string? GetEditedTaskName()
{
return EditedTaskName;
}
private void BtnEditTask_Click(object sender, RoutedEventArgs e)
{
if (LstBoxTasks.SelectedItem != null)
{
EditWindow editWindow = new EditWindow();
editWindow.Show();
//_viewModel.Tasks[LstBoxTasks.SelectedIndex].TaskName = editedTaskName;
}
}
}
}
This is the code for the C# file of the second window:
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 ToDoList
{
/// <summary>
/// Interaction logic for EditWindow.xaml
/// </summary>
public partial class EditWindow : Window
{
public EditWindow()
{
InitializeComponent();
var DemoMainWindow = this.DataContext;
}
private void BtnEdit_Click(object sender, RoutedEventArgs e)
{
((DemoMainWindow)Application.Current.MainWindow).EditedTaskName = EditTextBox.Text;
// _viewModel.Tasks[LstBoxTasks.SelectedIndex].TaskName = TxtUCEnteredTask.txtLimitedInput.Text;
}
}
}
When you create the view, create it's viewmodel before so that you can set the view's datacontext:
EditWindowViewModel vm = new EditWindowViewModel();
EditWindow editWindow = new EditWindow()
{
DataContext = vm;
};
editWindow.Show();
StringToChange = vm.EditBoxTextProperty;
Create a bindable property for stroing the editbox's text using INotifyPropertyCganged in the EditWindowViewModel (see this):
private string _editBoxTextProperty;
public string EditBoxTextProperty
{
get => _editBoxTextProperty;
set
{
if (_editBoxTextProperty != value)
{
_editBoxTextProperty = value;
OnPropertyChanged();
}
}
}
In the EditWindow xaml, use binding to connect the editbox's text value to your EditBoxTextProperty.
<TextBox Text="{Binding Path=EditBoxTextProperty}"/>
Usefull links to build a proper WPF application: DataBinding MVVM Pattern
What I have found to be useful when having to interact between elements on different windows is using x:FieldModifier
<TextBox x:Name="textbox" x:FieldModifier="public" />
You can then access the element through the instance of you window
it will appear as WindowInstanceName.textbox

Close Windows on TextBox text change using Mvvm, Wpf,C#,Visual Studio

I want to execute a method on TextChange event and for specific text, I want to do something and close the window using MVVM
for example on this part of my code I want to close my window:
if (text.Equals("12345"))
{
//Exit from window
}
I know how can I do it from a button using a command, As I have in the code of the next example.
But how can I pass the window to a running property that binds to a text of the textbox?
or there is another way to close form?
I want to do it on the ViewModel and not the code behind to write my code as MVVM pattern close that I can
my XAML code :
<Window x:Class="PulserTesterMultipleHeads.UserControls.TestWindows"
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:PulserTesterMultipleHeads.UserControls"
mc:Ignorable="d"
Name="MainTestWindow"
Title="TestWindows" Height="450" Width="800">
<Grid>
<StackPanel>
<TextBox Text="{Binding Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"></TextBox>
<Button Command="{Binding EndTestExit}"
CommandParameter="{Binding ElementName=MainTestWindow}">Exit</Button>
</StackPanel>
</Grid>
</Window>
the code behind XAML :
using PulserTesterMultipleHeads.Classes;
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 PulserTesterMultipleHeads.UserControls
{
/// <summary>
/// Interaction logic for TestWindows.xaml
/// </summary>
public partial class TestWindows : Window
{
public TestWindows()
{
InitializeComponent();
DataContext = new TestWindowsMV();
}
}
}
View Model code :
using PulserTester.ViewModel.Base;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
namespace PulserTesterMultipleHeads.Classes
{
public class TestWindowsMV : INotifyPropertyChanged
{
private string text;
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
//Exit from window
}
}
}
/// <summary>
/// for the example
/// </summary>
private ICommand _EndTestExit;
public ICommand EndTestExit
{
get
{
if (_EndTestExit == null)
{
_EndTestExit = new GenericRelayCommand<Window>((window) => EndTestExitAction(window));
}
return _EndTestExit;
}
}
private void EndTestExitAction(Window window)
{
window.Close();
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
************************* Edit as the answer ****************************
The change in ModelView :
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
CloseAction();
}
}
}
The change in code behind:
public TestWindows()
{
InitializeComponent();
DataContext = new TestWindowsMV();
if (((TestWindowsMV)DataContext).CloseAction == null)
((TestWindowsMV)DataContext).CloseAction = new Action(this.Close);
}
It is kind of hard with MVVM but what you can do is create an Event inside of your ViewModel and attach a function that will close your window in code behind of your View. Then you will be able to call your event inside of ViewModel whenever you need to close the window (or do something else that is more convenient to do in View rather than in ViewModel)
The cleanest way to close a View from the ViewModel is to use an attached property
public static class perWindowHelper
{
public static readonly DependencyProperty CloseWindowProperty = DependencyProperty.RegisterAttached(
"CloseWindow",
typeof(bool?),
typeof(perWindowHelper),
new PropertyMetadata(null, OnCloseWindowChanged));
private static void OnCloseWindowChanged(DependencyObject target, DependencyPropertyChangedEventArgs args)
{
if (!(target is Window view))
return;
if (view.IsModal())
view.DialogResult = args.NewValue as bool?;
else
view.Close();
}
public static void SetCloseWindow(Window target, bool? value)
{
target.SetValue(CloseWindowProperty, value);
}
public static bool IsModal(this Window window)
{
var fieldInfo = typeof(Window).GetField("_showingAsDialog", BindingFlags.Instance | BindingFlags.NonPublic);
return fieldInfo != null && (bool)fieldInfo.GetValue(window);
}
}
which you can then bind to an appropriate property in your ViewModel
<Window
x:Class="...
vhelp:perWindowHelper.CloseWindow="{Binding ViewClosed}">
private bool? _viewClosed;
public bool? ViewClosed
{
get { return _viewClosed; }
set { Set(nameof(ViewClosed), ref _viewClosed, value); }
}
More details on my recent blog post.
You have almost everything you need already implemented. All you really need to do is call private void EndTestExitAction(Window window) from your setter and supply window its value during construction:
public string Text {
get {
return text;
} set {
text = value;
if (text.Equals("12345"))
{
EndTestExitAction(window)
}
}
}
where window is a property of your View Model.

Why PropertyChanged could be null when gets binded?

here is the problem i am encountering, i will use the class names in my demo to describe my problem:
i have to show something on a datagrid, as a view of Item. but the Item itself is a wrapper class of the real data source, Dummy.
Container is the manager of all Dummy's, it will call Poll periodically(in my demo, 1s) and it internally queries the remote server to decide the current value(in demo, i simply flip the boolean). and after that, Container will go through all Item's and Notify them changes may be made.
but my problem is, the if branch in Notify called by Container won't get in, since PropertyChanged is null! but if i change it in the DataGrid, i.e. dg, by double click, this event gets subscribed. so my problem is, how can i successfully notify in Container? is there any a way to make DataGrid subscribe to PropertyChanged all the time?
btw, if i use a debugger to get in, they are null too.
Following is my demo code:
xaml:
<Window x:Class="WpfApplication6.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>
<DataGrid x:Name="dg" Margin="0,0,0,35"/>
<Button Content="Button" Margin="0,0,10,10" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Right" Width="75" Click="Button_Click"/>
</Grid>
</Window>
c# part:
using System;
using System.Collections.Generic;
using System.ComponentModel;
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;
using System.Windows.Threading;
namespace WpfApplication6
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private Container _container;
public MainWindow()
{
InitializeComponent();
_container = new Container();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
dg.ItemsSource = _container.GetItems();
}
}
public class Dummy
{
public Dummy()
{
_done=false;
}
private bool _done;
public bool Done {
get { return _done; }
// set will trigger something remotely too.
set { _done = value; }
}
public void Poll() { _done=!_done;}
}
public class Item : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private Dummy dummy;
public Item(Dummy dum)
{
dummy = dum;
}
public bool Done
{
get { return dummy.Done; }
set
{
dummy.Done = value;
Notify();
}
}
public void Notify()
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs("Done"));
}
}
public class Container
{
private List<Dummy> dummies;
private DispatcherTimer _updateTimer;
public Container()
{
dummies = (from i in Enumerable.Range(0, 10)
select new Dummy()).ToList();
}
private IEnumerable<Item> items;
public Item[] GetItems()
{
if (_updateTimer != null)
_updateTimer.Stop();
items=dummies.Select(x => new Item(x));
_updateTimer = new DispatcherTimer();
_updateTimer.Interval = TimeSpan.FromSeconds(1);
_updateTimer.Tick += (_1, _2) =>
{
foreach (var item in dummies)
{
item.Poll();
}
foreach (var item in items)
{
item.Notify();
}
};
_updateTimer.Start();
return items.ToArray();
}
}
}

Updating wpf parent window after some action on another window

i have one wpf window called usermanagement and there is a listbox showing all the users, i have one button in usermanagement window called add user and when i click on that new window opens called adduser, in this window there are input fields to add new user, what i need when i save data and this adduser window close then the usermanagement window update the listbox, means users again update (the new added user should show there after adding). at the moment i needed to open the usermanagement window again to see the new added user. Thanks!
here is the code below
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;
using System.Collections;
using Model;
namespace Views
{
/// <summary>
/// Interaction logic for frmUserManagement.xaml
/// </summary>
public partial class frmUserManagement : Window
{
public frmUserManagement()
{
InitializeComponent();
}
public void window_loaded(object sender, RoutedEventArgs e)
{
load_users();
}
public void load_users()
{
RST_DBDataContext conn = new RST_DBDataContext();
var users = (from s in conn.TblUsers
select s.UserName).ToList();
Login_Names.ItemsSource = users;
}
private void add_user(object sender, RoutedEventArgs e)
{
adduser AddUserWindow = new adduser();
AddUserWindow.ShowDialog();
}
}
}
in xaml file there is
<Grid>
<ListBox Name="Login_Names" HorizontalAlignment="Left" Height="337" Margin="10,47,0,0" Padding="0,0,0,0" VerticalAlignment="Top" Width="156">
<Button Content="Add" HorizontalAlignment="Left" Margin="10,404,0,0" VerticalAlignment="Top" Width="75" Click="add_user"/>
</Grid>
Do insert operations inside main window (UserManagmentWindow):
UserManagmentWindow.cs:
// Inside add button handler open adduser window as dialog box...
var result = adduser.ShowDialog();
if(result == true){
// user pressed OK button...
// insert new user in database
// refresh UserManagmentWindow
}
Post your code if you need more details...
You can declare an event in Your AddUser window, and trigger the event when you press the button.
First define your EventArgs child class
public class AddUserEventArgs : EventArgs
{
public User AddInfo { get; private set; }
public AddUserEventArgs(User info)
{
this.AddInfo = info;
}
}
In your AddUser class:
public event EventHandler<AddUserEventArgs> AddedUser;
private void Button_Click(Object sender, RoutedEventArgs)
{
User info = new User();
// Realize your validation here...
// If validation is Okay, then..
if (OK)
{
if (this.AddedUser != null)
this.AddedUser(this, new AddUserEventArgs(info));
this.Close();
}
}
In your UserManagement class:
var window = new AddUserWindow();
window.AddedUser += (sender, e) =>
{
// Add the info to your ObservableCollection.
this.collection.Add(e.AddInfo);
}
window.ShowDialog();

Custom WF4 Activity: Why e.Handled = true in DoubleClick don't stops bubbling

Hallo I'm using custom WF4 activity which can be nested by self. I have to catch a double-click event, so I rewrote OnPreviewMouseDoubleClick method. My problem is that when activity is inside the other activity and am the double click to inner one, the double click is invoked on both of them. I set the e.Handled = true but it doesn't work. How can I stop to execute the double click event on parent activities.
Here is my example of codes:
ActivityDesigner1.xaml
<sap:ActivityDesigner x:Class="ActivityDesignerLibrary1.ActivityDesigner1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sap="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"
xmlns:sapv="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation">
<Grid>
<sap:WorkflowItemsPresenter Items="{Binding Path=ModelItem.Activities}">
<sap:WorkflowItemsPresenter.SpacerTemplate>
<DataTemplate>
<Label HorizontalAlignment="Center" Content="Drop activity here." FontStyle="Italic" Foreground="DarkGray" />
</DataTemplate>
</sap:WorkflowItemsPresenter.SpacerTemplate>
</sap:WorkflowItemsPresenter>
</Grid>
</sap:ActivityDesigner>
ActivityDesigner1.xaml.cs
using System.Windows;
using System.Windows.Input;
namespace ActivityDesignerLibrary1
{
public partial class ActivityDesigner1
{
public ActivityDesigner1()
{
InitializeComponent();
}
protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
e.Handled = true;
base.OnPreviewMouseDoubleClick(e);
MessageBox.Show(this.GetHashCode().ToString());
}
}
}
CodeActivity1.cs
using System;
using System.Activities;
using System.Activities.Statements;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace ActivityDesignerLibrary1
{
[Designer(typeof(ActivityDesigner1))]
public sealed class CodeActivity1 : CodeActivity
{
private Sequence innerSequence = new Sequence();
public Collection<Activity> Activities
{
get
{
return this.innerSequence.Activities;
}
}
protected override void Execute(CodeActivityContext context)
{
throw new NotImplementedException();
}
}
}
Remark in Makus link continues like this:
Control authors who want to handle mouse double clicks should use the MouseLeftButtonDown event when ClickCount is equal to two. This will cause the state of Handled to propagate appropriately in the case where another element in the element tree handles the event.
So I created this workaround:
using System.Windows;
using System.Windows.Input;
using System.Activities.Presentation;
using System.Windows.Media;
namespace ActivityDesignerLibrary1
{
public partial class ActivityDesigner1
{
public ActivityDesigner1()
{
InitializeComponent();
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
FrameworkElement fe = e.OriginalSource as FrameworkElement;
if (fe != null)
{
object original = fe.DataContext;
ActivityDesigner baseActivityDesigner = original as ActivityDesigner;
if (baseActivityDesigner == null)
{
baseActivityDesigner = this.ActivityDesignerFinder((DependencyObject)e.OriginalSource);
}
if (baseActivityDesigner != null)
{
MessageBox.Show(baseActivityDesigner.GetHashCode().ToString());
e.Handled = true;
}
}
}
}
private ActivityDesigner ActivityDesignerFinder(DependencyObject dependencyObject)
{
while (dependencyObject != null)
{
if (dependencyObject is ActivityDesigner)
{
return (ActivityDesigner)dependencyObject;
}
dependencyObject = VisualTreeHelper.GetParent(dependencyObject);
}
return null;
}
}
}
MSDN has answer for you:
link
Quote: Although this routed event (Control.MouseDoubleClick Event) seems to follow a bubbling route through an element tree, it actually is a direct routed event that is raised along the element tree by each UIElement. If you set the Handled property to true in a MouseDoubleClick event handler, subsequent MouseDoubleClick events along the route will occur with Handled set to false. This is a higher-level event for control consumers who want to be notified when the user double-clicks the control and to handle the event in an application.
Have you tried using a static bool for the handled property?
I remember having a same issue with drag&drop and solved it this way.

Categories